RGB 2 RYB command - G'MIC

I’m developing new command codes like rgb2ryb and ryb2rgb to expand on some filters and I’m not sure what I’m doing. Different formulas lead to very different result. I want to know which one is correct. On the other hand, doing this helped me learn a bit of math and understand them a bit easier.

rgb2ryb1 : split_opacity l[0] +compose_channels[0] min to_rgb -.. . +compose_channels[0] max to_rgb +l[0] s c rm. a c compose_channels min endl -[0] . to_color[0] f[0] "VC=(G+B)>0?1:0;[R,VC?G/2:G,VC?B/2:B]" s[0] c +. [1] +[2] [1] rv[1,5] rm. a[0-2] c n[0] {im#0<0?0:im#0},{iM#0} k[0] endl a c

Reference - ryb2rgb.R | Políticamente Correcto

ryb2rgb: / 255 to_color f 
"cubicInt(t,vA,vB) = (weight=t*t*(3-2*t);vA+weight*(vB-vA));
getR(iR,iY,iB) = (x0=cubicInt(iB,1,.163);x1=cubicInt(iB,1,0);x2=cubicInt(iB,1,.5);x3=cubicInt(iB,1,.2);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
getG(iR,iY,iB) = (x0=cubicInt(iB,1,.373);x1=cubicInt(iB,1,.66);x2=cubicInt(iB,0,0);x3=cubicInt(iB,.5,094);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
getB(iR,iY,iB) = (x0=cubicInt(iB,1,.6);x1=cubicInt(iB,0,.2);x2=cubicInt(iB,0,0.5);x3=cubicInt(iB,0,0);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
Rn=getR(R,G,B);
Gn=getG(R,G,B);
Bn=getB(R,G,B);
E=[Rn,Gn,Bn,A];E*255"

Reference - node-ryb2rgb/ryb2rgb.js at master · bahamas10/node-ryb2rgb · GitHub

Perhaps read up on:
Subtractive color - Wikipedia
handprint : colormaking attributes

I read, but I’m looking for something that’s pretty easy to translate via G’MIC. The ones I found either are very tricky to translate or perhaps incompatible like the bahamas10 ones from the rgb2ryb and ryb2rgb. I guess I will have to do some mathematics to make my own version of the bahamas10 since it’s the easiest to code. Actually, I think the second one could be easy to translate since it’s the very same as this one found in here - inverse - RYB and RGB Color Space Conversion - Mathematics Stack Exchange, I’ll do the math here now.

Depending on the colour conversion, there is almost always some debate over which is correct. The links that I included talk more about the theory so that you can decide for yourself which is better. As for implementation, I am sure you are up to the challenge. :stuck_out_tongue:

I think I could implement it pretty soon. From the info I found on stack exchange. I came up with this.

RYB  ---- RGB
f(0,0,0)=(1,1,1)
f(0,0,1)=(0.163,0.373,0.6)
f(0,1,0)=(1,1,0)
f(0,1,1)=(0,0.66,0.2)
f(1,0,0)=(1,0,0)
f(1,0,1)=(.5,.5,0)
f(1,1,0)=(1,.5,0)
f(1,1,1)=(0.2,0.094,0.0)

/ 255 to_color f 
"cubicInt(t,vA,vB) = (weight=t*t*(3-2*t);vA+weight*(vB-vA));
getR(iR,iY,iB) = (x0=cubicInt(iB,1,.163);x1=cubicInt(iB,1,0);x2=cubicInt(iB,1,.5);x3=cubicInt(iB,1,.2);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
getG(iR,iY,iB) = (x0=cubicInt(iB,1,.373);x1=cubicInt(iB,1,.66);x2=cubicInt(iB,0,0);x3=cubicInt(iB,.5,.094);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
getB(iR,iY,iB) = (x0=cubicInt(iB,1,.6);x1=cubicInt(iB,0,.2);x2=cubicInt(iB,0,0.5);x3=cubicInt(iB,0,0);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
Rn=getR(R,G,B);
Gn=getG(R,G,B);
Bn=getB(R,G,B);
E=[Rn,Gn,Bn,A];E*255"

RGB ---- RYB
f(0,0,0)=(1,1,1)
f(0,0,1)=(0,0,1)
f(0,1,0)=(1,1,.483)
f(0,1,1)=(0,0.053,0.210)
f(1,0,0)=(1,0,0)
f(1,0,1)=(.309,0,469)
f(1,1,0)=(0,1,0)
f(1,1,1)=(0,0,0)

/ 255 to_color f 
"cubicInt(t,vA,vB) = (weight=t*t*(3-2*t);vA+weight*(vB-vA));
getR(iR,iY,iB) = (x0=cubicInt(iB,1,0);x1=cubicInt(iB,1,0);x2=cubicInt(iB,1,.309);x3=cubicInt(iB,0,0);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
getG(iR,iY,iB) = (x0=cubicInt(iB,1,0);x1=cubicInt(iB,1,.053);x2=cubicInt(iB,0,0);x3=cubicInt(iB,1,0);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
getB(iR,iY,iB) = (x0=cubicInt(iB,1,1);x1=cubicInt(iB,.483,.210);x2=cubicInt(iB,0,0.469);x3=cubicInt(iB,0,0);y0=cubicInt(iY,x0,x1);y1=cubicInt(iY,x2,x3);cubicInt(iR,y0,y1));
Rn=getR(R,G,B);
Gn=getG(R,G,B);
Bn=getB(R,G,B);
E=[Rn,Gn,Bn,A];E*255"

Actually, it doesn’t work going from RGB to RYB, then RYB to RGB. I guess the process of RGB to RYB is irreversible. Damaged basically. But RYB to RGB has real potential application for coloring reference.

I’ve added commands rgb2ryb and ryb2rgb in the standard library.
I’ve also added the ryb colorspace as a valid argument for command apply_channels, as well as added it to the filters that use it.

I’ve recoded the RGB<->RYB transformations from the Javascript source provided on this page : Color Space

Let me know if you encounter issues with these new commands.

1 Like

I like how that works as there’s no color loss info or negligible at all upon conversion. The cyan isn’t lost here. There’s more applications for that solely because of that observation. Luminosity could be inverted as a separate command to stimulate “subtraction property”, and one could find that the addition varient more useful because it reduce the need to change luminosity property.

My own version is more based on actual painting due to the subtraction property and being based on actual painting color wheel. So, I guess for my own version, it could be rgb2ryb_p and ryb2rgb_p where p means pigment-based. My own version is not very useful with other things other than being a helper for generating references for ryb painting-based works, but too limited on that.

Here’s the RYB bar I made for PDN forum as a reference for comparison using the cube-based code -

I guess this topic is solved from just my point of view.


@David_Tschumperle - I just figured that how one can make a subtraction-based model using existing command. But, I think that there should be new commands like rgb2sryb, and sryb2rgb instead that uses these code. s means it’ll be based on the subtractive model.

rgb2sryb: rgb2ryb ac "f "255-i"",hsl_l 
sryb2rgb: ryb2rgb ac "f "255-i"",hsl_l

Not sure how to do the ac command version since it’s using ac in of by itself.

@Reptorian I am kind of stumped by your post. Perhaps including a link to the appropriate thread might shed some light, or “explainlikeimfive”.

On another forum, a person was trying to create a way to fill image based on palettes on ryb space.

The RYB he provided was not very accurate, and performs worse than the implemented ryb conversion cli tools in current g’mic, and the cubic interpolation which was my own. Less smoother hue transition, worse chroma transition. I was testing my own implementation vs the OP of that thread. The cubic interpolation has the advantage of being actually based on actual painting, and did performed better than the OP approach - http://vis.computer.org/vis2004/DVD/infovis/papers/gossett.pdf . Original PDF is in that link, and it demonstrates how actual painting based on ryb model can be stimulated.

On the second part of the post, currently the ryb conversion cli tools in gmic is based on additive logic as evidenced by @David_Tschumperle . The code with ryb2rgb alongside with ac"",hsl_l provides a way to convert image to subtractive ryb model. It makes sense to provide subtractive ryb as ryb is usually based on subtractive model.

It is the second part that I have trouble understanding. The RYB model is subtractive. My assumption is that it is the mixing that makes the model subtractive and not the conversion. I am not a digital painter, so I might need an example.