# rgb2hsy.m

RGB2HSY(INPICT, {MODE})
Convert an rgb image to a normalized polar adaptation of YPbPr
This is offered as an unconventional alternative to HuSL or
LCH for general image editing without causing large perceived
brightness distortions when changing hue/saturation

This actually uses YPbPr just for numeric convenience
Chroma is normalized and clamped in this method.

Normalization forces color points to stay within the RGB cube.
This prevents clipping when rotating H for points with high S.
Furthermore, it mimics HuSL behavior in that S is bounded.
One could debate whether this is desired behavior.

HSYp variant is normalized and bounded to the maximum biconic subset of the projected RGB space.
This means HSYp avoids distortion of the chroma space when normalizing, preserving the uniformity
of the parent space. Unfortunately, this also means it can only render colors near the neutral axis (pastels).

HSYn variant is still normalized WRT the maximal rotationally-symmetric subset as in HSYp
but specified chroma is bound only by the extent of the projected RGB space.  In this mode,
100% S still refers to the extent of HSYp, but color points can be specified with S>100%,
so long as they stay within the RGB cube. This allows uniform access to the entire projected RGB space,
unlike HSYp; it also allows for data truncation to occur before conversion, unlike YPbPr methods.

HSYp and HSYn are mostly useful for relative specification of uniform colors.

MODE specifies the normalization and bounding behavior.
'normal' normalizes and bounds to the extent of the projected RGB space (HSY) (default)
'pastel' normalizes and bounds to the maximal biconic subset of the projected RGB space (HSYp)
'native' normalizes as in 'pastel' mode, but bounds as in 'normal' mode (HSYn)

Output is of type double, in the range:
H \in [0 360)
S \in [0 1]
Y \in [0 1]


RGB2HSY() and HSY2RGB() can be used for conversion between RGB and my own version of HSY. This method uses a polar adaptation of YPbPr wherein the chroma is normalized and bounded by the extent of the RGB cube (a subset of the entire YPbPr space). Like HuSL, this minimizes the occurrence and severity of clipping. A point near the surface of the RGB cube will follow a noncircular path with hue rotation and a nonvertical path with Y scaling. Dramatic oversaturation merely pushes the point radially to the boundary of the RGB cube. In an unbounded method such as YPbPr or LCH, the point would be pushed far outside the RGB gamut and then when clipping occurs on return to RGB, it would be remapped to some point distant from its exit.

It's worth noting as well that in the output, H in HSY is aligned to the red corner of the RGB cube instead of to the PbPr plane. There would otherwise be a 108.6 degree offset between H in HSY and H in other models.

For examples of image manipulation with these methods, see IMBLEND() and IMTWEAK() pages.

Example 1:
Generate a test gradient to show color uniformity in HSY and HSYp compared to HSL. Although HSYp has restricted chroma, the results maintain the uniformity of the parent space. The low resolution of the gradient makes it easier to identify perceptual change as hue is varied. Compare to the HuSLp examples. Although not as uniform, HSYp has access to more saturated colors. In general, HSYp covers a greater fraction of its parent space than either HuSLp method.

steps=[40 20];

h=0:360/steps(1):(360-360/steps(1));
y=0:1/steps(2):(1-1/steps(2));
[H Y]=meshgrid(h,fliplr(y));
S=ones(size(Y));

hslrgb=colorspace('


Example 2:
Plot the volume enclosed by the range of HSYp as a subset of the projected RGB space in YPbPr

Lbreak=0.50195313;
Cbreak=0.28211668;
L=0:0.01:1;
Cp=zeros(size(L));

mk=(L<Lbreak);
Cp(mk)=Cbreak/Lbreak*L(mk);
Cp(~mk)=Cbreak-Cbreak/(1-Lbreak)*(L(~mk)-Lbreak);

stp=100;
l=0:1/stp:1; h=0:360/stp:360;
[L H]=meshgrid(l,h);

st=size(Cp)-1;
Lp=round(L*st(2))+1;
C=Cp(Lp);

X=C.*cos(H*pi/180);
Y=C.*sin(H*pi/180);

csview('ypbpr','invert',1,'alpha',0.5);
surf(X,Y,L,'facecolor',[1 1 1])


Example 3:
Plot the upper and lower faces of the HuSLpab and HuSLpuv bicones and compare to HSYp.

no example code for this one, sorry.