Reptorian G'MIC Filters

I just managed to do be able to manipulate multiple channels.


s. c

+[-4] _fx_vibrato_texture 1,1,3,1.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,5
+[-3] _fx_vibrato_texture 1,1,3,2.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,3
+[-2] _fx_vibrato_texture 1,1,1,1,1.25,1.25,1,0,0,.1,.5,1,0,1,1,1,2
+[-1] _fx_vibrato_texture 1,1,4,1,1.25,1.25,1,0,0,.1,.5,1,0,1,1,1,2

a[-4--1] c


Now, I think I know how to make the filter I want, and I’ll get started on it tomorrow.

EDIT: Actually, no, I still have to extract the channel as that would probably lead to better result. Guess, I’ll have to do a long search to find out on how to extract channel.

Consider sh, that will allow you to split out channels in a way which will make your command run faster.

I’m looking at it, but getting errors. I did noticed that I extracted just one channel if I put shared before s. c

I guess I’ll have to use this instead -


s. c

+[-4] [0]  _fx_vibrato_texture 1,1,3,1.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,5
+[-3] [1] _fx_vibrato_texture 1,1,3,2.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,3
+[-2] [2] _fx_vibrato_texture 1,1,1,1,1.25,1.25,1,0,0,.1,.5,1,0,1,1,1,2
+[-1] [3] _fx_vibrato_texture 1,1,4,1,1.25,1.25,1,0,0,.1,.5,1,0,1,1,1,2

a[-4--1] c


Also, I noticed by removing the additional command, I seem to be getting really bad result.

See here. That’s not how it’s suppose to look like.

Try using sh for each channel using a repeat loop. Regarding the brightness, that might be due to the alpha channel being used as the V channel in the hsv2rgb command. Try splitting away the opacity and processing that in a separate block before appending it to the image’s spectrum again.

[0] s. c
a[1-4] c

Here is an attempt. I think I’m learning how to work with channels now.

Final attempt

s. c
a[1-3] c
a[0,1] c

Next up, I’ll probably learn the repeat command though I think it’s just easier to code the filter without repeating.

s c
-_fx_vibrato_texture[0] 1,1,3,2.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,3
-_fx_vibrato_texture[1] 1,1,3,1.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,5
-_fx_vibrato_texture[2] 1,1,3,1.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,5
-_fx_vibrato_texture[3] 1,1,3,1.5,1.25,1.25,1,0,0,.7,.5,1,0,1,1,0,5
a[0-2] c
a[0,1] c

Now, I think I have a code to work from here. By the way, there seem to be a problem with lch here. cmy as well.

Actually, I think I should create separate versions of the filter to make things a lot easier to code.

@Reptorian Learning the syntax was challenging for me as well. Also, there are many ways of going about it. This is what I came up with as an example. All you would need to do is replace * with _fx_vibrato_texture and 1.5 with your parameters. Note that for LCh conversions, the commands have an option to them (upon my request), which selects the illuminant. If you don’t care about which to use, then just use , as input, which sets the option to the default one. An error pops up because your commands are incomplete or there is a mismatch of arguments.

  sample tiger to_rgba
    rgb2lch , split c
    *[0] 1.5
    *[1] 1.5
    *[2] 1.5
    append c lch2rgb ,
  *[1] 1.5 append c
1 Like

Wow, I never knew about the local thing. That would make things so much easier, and it gets around the issue of color space model not having alpha. Also, I think that would definitely make it easier to work with alpha channel and disable channels for editing.

I have combined the two vibrato filter into one. There’s a roadblock though. Actually, alpha processing don’t seem to work on the condition of modifying multiple channels at once. Hmm…

#@gui _
#@gui Vibrato: fx_vibrato, _fx_vibrato_preview(0)
#@gui : note = note("This is the advanced version of the Vibrato filter. If you do want to manipulate multiple channels at once, use <u>Vibrato - Basic</u> filter. <i>Note: Disable channel mulplication for non-transparent images.</i> \n\n")
#@gui : note = note("This filter is the one of the G'MIC version of <b>MadJik's</b> <i>Paint.NET plugin</i>")
#@gui : sep = separator()
#@gui : 1. Colour Space = choice("RGB", "CMY", "HSI", "HSL", "HSV", "LAB", "LCH", "YCbCr", "YCbCr-Glic", "YUV", "YIQ", "XYZ", "Bayer")
#@gui : sep = separator()
#@gui : 2. Manipulate multiple channels at once? = bool(1)
#@gui : 3. Process Channel 1? = bool(1)
#@gui : 4. Process Channel 2? = bool(1)
#@gui : 5. Process Channel 3? = bool(1)
#@gui : 6. Process Alpha Channel? = bool(1)
#@gui : 7. Inherit Alpha? = bool(1)
#@gui : 8. X-Orientation = bool(1)
#@gui : 9. Y-Orientation = bool(1)
#@gui : 10. U- Factor = float(.85,.1,15)
#@gui : 11. V- Factor = float(.85,.1,15)
#@gui : 12. X-Scale Factor = float(1,.1,15)
#@gui : 13. Y-Scale Factor = float(1,.1,15)
#@gui : 14. XY-Scale Factor = float(1,.1,3)
#@gui : 15. Percentage-Based X Pixel Shift = float(0,-200,200)
#@gui : 16. Percentage-Based Y Pixel Shift = float(0,-200,200)
#@gui : 17. Elevation = float(.7,-100,100)
#@gui : 18. Multiply Blending = bool(0)
#@gui : 19. Invert Vibrato = bool(0)
#@gui : 20. Vibrato Blending Factor = float (100,0,100)
#@gui : 21. Channel Influence Factor = float(1,-8,8)
#@gui : 22. Final Channel Modulos Multiplication Factor = float(1,1,32)
#@gui : sep = separator()
#@gui : note = note("- <b>Channel #1</b> - ")
#@gui : 23. Process Channel? = bool(1)
#@gui : 24. X-Orientation = bool(1)
#@gui : 25. Y-Orientation = bool(1)
#@gui : 26. U- Factor = float(.85,.1,15)
#@gui : 27. V- Factor = float(.85,.1,15)
#@gui : 28. X-Scale Factor = float(1,.1,15)
#@gui : 29. Y-Scale Factor = float(1,.1,15)
#@gui : 30. XY-Scale Factor = float(1,.1,3)
#@gui : 31. Percentage-Based X Pixel Shift = float(0,-200,200)
#@gui : 32. Percentage-Based Y Pixel Shift = float(0,-200,200)
#@gui : 33. Elevation = float(.7,-100,100)
#@gui : 34. Multiply Blending = bool(0)
#@gui : 35. Invert Vibrato = bool(0)
#@gui : 36. Vibrato Blending Factor = float (100,0,100)
#@gui : 37. Channel Influence Factor = float(1,-8,8)
#@gui : 38. Final Channel Modulos Multiplication Factor = float(1,1,32)
#@gui : sep = separator()
#@gui : note = note("- <b>Channel #2</b> - ")
#@gui : 39. Process Channel? = bool(1)
#@gui : 40. X-Orientation = bool(1)
#@gui : 41. Y-Orientation = bool(1)
#@gui : 42. U- Factor = float(.85,.1,15)
#@gui : 43. V- Factor = float(.85,.1,15)
#@gui : 44. X-Scale Factor = float(1,.1,15)
#@gui : 45. Y-Scale Factor = float(1,.1,15)
#@gui : 46. XY-Scale Factor = float(1,.1,3)
#@gui : 47. Percentage-Based X Pixel Shift = float(0,-200,200)
#@gui : 48. Percentage-Based Y Pixel Shift = float(0,-200,200)
#@gui : 49. Elevation = float(.7,-100,100)
#@gui : 50. Multiply Blending = bool(0)
#@gui : 51. Invert Vibrato = bool(0)
#@gui : 52. Vibrato Blending Factor = float (100,0,100)
#@gui : 53. Channel Influence Factor = float(1,-8,8)
#@gui : 54. Final Channel Modulos Multiplication Factor = float(1,1,32)
#@gui : sep = separator()
#@gui : note = note("- <b>Channel #3</b> - ")
#@gui : 55. Process Channel? = bool(1)
#@gui : 56. X-Orientation = bool(1)
#@gui : 57. Y-Orientation = bool(1)
#@gui : 58. U- Factor = float(.85,.1,15)
#@gui : 59. V- Factor = float(.85,.1,15)
#@gui : 60. X-Scale Factor = float(1,.1,15)
#@gui : 61. Y-Scale Factor = float(1,.1,15)
#@gui : 62. XY-Scale Factor = float(1,.1,3)
#@gui : 63. Percentage-Based X Pixel Shift = float(0,-200,200)
#@gui : 64. Percentage-Based Y Pixel Shift = float(0,-200,200)
#@gui : 65. Elevation = float(.7,-100,100)
#@gui : 66. Multiply Blending = bool(0)
#@gui : 67. Invert Vibrato = bool(0)
#@gui : 68. Vibrato Blending Factor = float (100,0,100)
#@gui : 69. Channel Influence Factor = float(1,-8,8)
#@gui : 70. Final Channel Modulos Multiplication Factor = float(1,1,32)
#@gui : sep = separator()
#@gui : note = note("- <b>Alpha Channel #1</b> - ")
#@gui : 71. Process Channel? = bool(0)
#@gui : 72. X-Orientation = bool(1)
#@gui : 73. Y-Orientation = bool(1)
#@gui : 74. U- Factor = float(.85,.1,15)
#@gui : 75. V- Factor = float(.85,.1,15)
#@gui : 76. X-Scale Factor = float(1,.1,15)
#@gui : 77. Y-Scale Factor = float(1,.1,15)
#@gui : 78. XY-Scale Factor = float(1,.1,3)
#@gui : 79. Percentage-Based X Pixel Shift = float(0,-200,200)
#@gui : 80. Percentage-Based Y Pixel Shift = float(0,-200,200)
#@gui : 81. Elevation = float(.7,-100,100)
#@gui : 82. Multiply Blending = bool(1)
#@gui : 83. Invert Vibrato = bool(0)
#@gui : 84. Vibrato Blending Factor = float (100,0,100)
#@gui : 85. Channel Influence Factor = float(1,-8,8)
#@gui : 86. Final Channel Modulos Multiplication Factor = float(1,1,32)
#@gui : sep = separator(), Preview type = choice("Full","Forward horizontal","Forward vertical","Backward horizontal","Backward vertical","Duplicate top","Duplicate left","Duplicate bottom","Duplicate right","Duplicate horizontal","Duplicate vertical","Checkered","Checkered inverse")
#@gui : sep = separator(), note = note("<small>Author : <i>Reptorian</i>      Latest update: <i>2018/12/19</i>.</small>")

if {$1==1} rgb2cmy
elif {$1==2} rgb2hsi8
elif {$1==3} rgb2hsl8
elif {$1==4} rgb2hsv8
elif {$1==5} rgb2lab8
elif {$1==6} rgb2lch8
elif {$1==7} rgb2ycbcr
elif {$1==8} rgb2ycbcrglic
elif {$1==9} rgb2yuv8
elif {$1==10} rgb2yiq8
elif {$1==11} rgb2xyz8
elif {$1==12} rgb2bayer 0

s c

if {$2==1} 
if {$3==1} -vibrato[0] $8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22 fi
if {$4==1} -vibrato[1] $8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22 fi
if {$5==1} -vibrato[2] $8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22 fi
elif {$2==0} 
if {$23==1} -vibrato[0] $24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38 fi
if {$39==1} -vibrato[1] $40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54 fi
if {$55==1} -vibrato[2] $56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70 fi
a c

if {$1==1} cmy2rgb
elif {$1==2} hsi82rgb
elif {$1==3} hsl82rgb
elif {$1==4} hsv82rgb
elif {$1==5} lab82rgb
elif {$1==6} lch82rgb
elif {$1==7} ycbcr2rgb
elif {$1==8} ycbcrglic2rgb
elif {$1==9} yuv82rgb
elif {$1==10} yiq82rgb
elif {$1==11} xyz82rgb
elif {$1==12} bayer2rgb 0,0,0
if {2==1}
if {6==1} -vibrato[1] $8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$7,$19,$20,$21,$22 fi
elif {$2==0}
if {$71==1} -vibrato[1] $72,$73,$74,75,$76,$77,$78,$79,$80,$81,$82,$83,$84,$85,$86 fi
a c

repeat $! l[$>]
n 0,255 
f "
X=(($1?w-x+q:x+q)/w-.5) * 2 * 1/$5 * 1/$7;
Y=(($2?h-y+l:y+l)/h-.5) * 2 * 1/$6 * 1/$7;
Z=((X-Y) * (X-U) * (X+U) * (Y-V) * (Y+V))+ $10;
" n 0,255 mul $15 mod 256
endl done

_fx_vibrato_preview :
gui_split_preview "fx_vibrato ${1--2}",$-1

A sample of modifying Saturation and Value Channels at once:


I might have to rework on Vibrato again, but I don’t feel like doing that for at least a month. The one that I have at the moment is very good in most cases, but alpha processing is broken when multiple channels editing is on, and I’m not sure how to fix that. I have attempted to work on a new filter which is attached.

OOBS Filter.txt (4.5 KB)

Right now, it’s broken to hell. But, the work in progress shows something. The worse part is that I do not know how to fix it. All seem to point that it should really work. But, it doesn’t.

One thing that I found useful while testing commands is to keep it simple and go case by case and step by step. The more lines and variables your filter has the harder it is to figure out what is wrong. Usually, I have a console and text editor with line numbers open.

I always go step by step, and then slowly develop into more. The filter is functional, but broken. Evidence from what I see seem more has to do with fx_oobs. There is something odd going on with the if series on that section. I’ll get rid of alt choice for color space and see what happens. Doing that helps me salvage the vibrato filter.

Maybe simplify things by using apply_channels and letting the user choose up to _ number of channels to modify with the added bonus of choosing any channel from the colour models below.

I did looked at that, but I’ll guess I’ll experiment some more with that.

By the way, Vibrato bug has been fixed.

Vibrato.txt (7.0 KB)

Now, Vibrato is definitely the replacement to Vibrato Texture filter here and is ready for the next gmic version. A better version of that will be coming later as I realize multiply is too limiting, but alas not really interested in addressing that for now. The filter does a lot by itself though.

The reason that I mention it is that you could avoid the ifends and also run vibrato on any channel, not just the normal triplets or quads, allowing you to focus on other aspects of your filter.

I don’t know what is wrong with your alpha. I don’t like reading long filters. :blush: But if you follow the basic structure that I gave you, the alpha should be left untouched. If you want to manipulate it, then do it before your last append, which is basically reattaching the opacity back onto the RGB.

I intended for the alpha to be able to be altered by variables by the users.

I figured out how it works. The problem is that I need to specify color space and channels to work with. Plus, rgb_rb does not work. Neither does 1,0,0 which is more aligned with what I want to see as I am using booleans to allow users to disable or enable channels editing.

You are right: not all combinations work. You could add to the command yourself. See for reference.

What I am thinking is simpler than that though. Here is a sample:

  repeat $! local[$>]
    if $1 apply_channels "equalize",$1 fi
    if $2 apply_channels "equalize",$2 fi
    if $3 apply_channels "equalize",$3 fi
  endlocal done
gmic sp tiger chan_afre 3,4,5

This is for CLI; I didn’t include the GUI part. Basically, with chan_afre, you could apply equalize on any channel(s) you specify. chan_afre 3,4,5 works on rgb_r, rgb_g and rgb_b, which is also equivalent to 3,4,5. When you use the value 0, the if condition is false. See how simple it can be? You can replace equalize with anything including vibrato.

Actually, chan_afre 3,5,0 would be better than the theoretical “rgb_rb” because you can assign a separate vibrato command per if statement, whereas “rgb_rb” would do the same thing to rgb_r and rgb_b.


I am surprised to have thought of such a command. It makes a lot of sense though. I guess I am getting better at this. :partying_face:

It is also a testament to how accessible G’MIC scripting is. :+1: Remember, I am not programmer or math wizard, nor photographer, or anything else.

I guess there should be two separate version of that.
chan_afre_alt 1,1,0,1 would make workint with booleans values easier. That command would only affect rga of rgba. But, I don’t think it is too hard to do {$1==1:3?0}. Yeah, your idea would work. 4 value inputs would be nice. 5 values might by chan_afre_cmyka ?,?,?,?,? with 1 or 0.

4 values seem like the right number.

It is up to you how many channels you would like to support. Note that G’MIC doesn’t care about the opacity, or alpha, channel. To it, that is just another channel among other channels. I.e., all split_opacity does is separate the last channel from the image. So, if you are working on a multispectral image of say 9 bands, the 9th channel would be separated.

It is tricky when you have 3-5 possible channels in Krita. I don’t know how Krita works. Does it store values as RGB, LAB, RGBA, LABA, CMYK or CMYKA? What ranges are the channels? 0-255, 0-65535 or 0-1? Are the alphas in the same range? As you can see, your filter needs to take into account all of these scenarios, or at least the more likely cases.

Lastly, chan_afre doesn’t need to use Boolean values. The channel value doubles as the 1, so like in my example, chan_afre 3,5,0 actually means chan_afre 1,1,0 and selects the channels rgb_r and rgb_b. Hence in the GUI, all you would need to do is include a number of Channel = choice(...)s according to the number of inputs you anticipate the user to require.