imtweak.m

IMTWEAK(INPICT,COLORMODEL,CHANGEVEC)
	allows simplified manipulation of RGB images or triplets using a 
	specified color model.  

INPICT an RGB image, a 4-D image set or a 3-element vector (color triplet)
	can process multiple triplets (i.e. a color table)
	so long as triplets are row vectors and array is not 3-D

COLORMODEL is one of the following 
	'rgb' for operations on [R G B] in RGB
	'hsv' for operations on [H S V] in HSV 
	'hsi' for operations on [H S I] in HSI
	'hsl' for operations on [H S L] in HSL (as in GIMP <2.9)
	'hsy' for operations on [H S Y] in HSY using YPbPr
	'hsyp' for operations on [H S Y] in HSYp using YPbPr
	'huslab' for operations on [H S L] in HuSL using CIELCHab
	'husluv' for operations on [H S L] in HuSL using CIELCHuv
	'huslpab' for operations on [H S L] in HuSLp using CIELCHab
	'huslpuv' for operations on [H S L] in HuSLp using CIELCHuv
    'ypbpr' for operations on [Y C H] in polar YPbPr
	'lchab' for operations on [L C H] in CIELCHab
	'lchuv' for operations on [L C H] in CIELCHuv
	'lchsr' for operations on [L C H] in polar SRLAB2

	HuSL is an adaptation of CIELCHuv/CIELCHab with normalized chroma. 
		It is particularly useful for tasks such as avoiding out-of-gamut 
		values when increasing saturation or when rotating hue at high saturation.
	HSY method uses polar operations in a normalized luma-chroma model
		this has results very similar to HuSL, but is about 2.5x as fast.
	HuSLp and HSYp variants are normalized and bounded to the maximum biconic subset of the   
		projected RGB space. This means HuSLp/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). 
		These methods are mostly useful for relative specification of uniform colors.
	LCH and YPbPr operations are clamped to the extent of RGB by data truncation prior to conversion
	
CHANGEVEC is a 3-element vector specifying amounts by which color
	channels are to be altered.  Scaling is proportional for 
	all metrics except hue  In the case of hue, specifying 1.00 will
	rotate hue 360 degrees.  Assuming an HSL model, CHANGEVEC=[0 1 1]
	results in no change to INPICT.  CHANGEVEC=[0.33 0.5 0.5] results
	in a 120 degree hue rotation and a 50% decrease of saturation and
	lightness. For channels other than hue, specifying a negative value 
	will invert the channel and then apply the specified scaling

CLASS SUPPORT:
Supports 'uint8', 'uint16', 'int16', 'single', and 'double'
			

This is a general purpose function used for adjusting colors of images, individual RGB triplets, or color tables. IMTWEAK() supports operations in the expected HSL model, but can also operate on many other color models. Operations in RGB are useful primarily when needing to adjust or invert the channels of an RGB image independently. HSL and HSI have some advantages over HSV, and are faster than LCH or HuSL. HuSL and LCH methods often yields better results but are significantly slower than other methods. HSY has results similar to HuSL, but with better speed.

An unbounded LCH method is potentially lossy; that is, color points are not restrained to the limits of the RGB gamut for normal datatype ranges. When out-of-gamut points are clipped on conversion to RGB, they tend to be mapped to locations far away from the point where they left the space. While maintaining a LCH working environment and converting to RGB only for final output would be ideal, These tools are all designed to be stand-alone with RGB input and output. As such, LCH methods are truncated. This results in good appearance with one operation, but the consequences of truncation tend to accumulate with repeated operations. For instance, repeated incremental hue adjustment will tend to compress the chroma range of an image to the extent of the HuSLp bicone since truncated information is unrecoverable. HuSL methods may be a useful compromise in these cases, despite their chroma distortion.

HuSL and HSY methods are attempts at creating convenient bounded polar color models like HSV or HSL, but which utilize transformations of the input RGB space with better color/brightness separation. HuSL is a variant of CIELCH wherein chroma is normalized to the extent of the RGB gamut. Similarly, my own HSY method uses a polar conversion of YPbPr wherein C is normalized to the RGB cube. Both methods constrain color points to reduce the effect of clipping, though HSY is much faster.

As to be expected, most of these methods perform poorly for large brightness adjustments. For significant brightness adjustments, consider using a levels/curves tool instead.

 

Example 1:
Do a partial desaturation of an image using HSV, HSI, HSL, YPP, LCH, HSY, and HuSL methods. Concatenate the images for easy comparison.

Note how desaturation in HSV tends to cause bright regions to lose contrast detail. Other methods have better performance for decreasing saturation. Keep in mind the differences between V, L, I, and Y, and note the detail captured on the highlights of the orange paint bottle and the orange areas of the pcb in the hand. Compare to the results shown on the MONO() demo page.

inpict=imread('sources/blacklight2.jpg');

cvec=[0 0.3 1];
hsvpict=imtweak(inpict,'hsv',cvec);
hsipict=imtweak(inpict,'hsi',cvec);
hslpict=imtweak(inpict,'hsl',cvec);
ypppict=imtweak(inpict,'ypbpr',fliplr(cvec));
hsypict=imtweak(inpict,'hsy',cvec);
lchabpict=imtweak(inpict,'lchab',fliplr(cvec));
lchuvpict=imtweak(inpict,'lchuv',fliplr(cvec));
huslabpict=imtweak(inpict,'huslab',cvec);
husluvpict=imtweak(inpict,'husluv',cvec);

R1=cat(2,hsvpict,hsipict,hslpict);
R2=cat(2,ypppict,lchabpict,lchuvpict);
R3=cat(2,hsypict,huslabpict,husluvpict);
comparison=cat(1,R1,R2,R3);

subplot_tight(1,1,1);
imshow(255-comparison)
				
 
 

Example 2:
Increase saturation/chroma using HSV, HSI, HSL, YPP, LCH, HSY, and HuSL methods. Concatenate the images for easy comparison.

Note how increasing saturation causes distortion of the lightness in the HSV, HSI methods. LCH and HuSL methods see limited effect from severe oversaturation.

inpict=imread('sources/blacklight2.jpg');

cvec=[0 3 1];
hsvpict=imtweak(inpict,'hsv',cvec);
hsipict=imtweak(inpict,'hsi',cvec);
hslpict=imtweak(inpict,'hsl',cvec);
ypppict=imtweak(inpict,'ypbpr',fliplr(cvec));
hsypict=imtweak(inpict,'hsy',cvec);
lchabpict=imtweak(inpict,'lchab',fliplr(cvec));
lchuvpict=imtweak(inpict,'lchuv',fliplr(cvec));
huslabpict=imtweak(inpict,'huslab',cvec);
husluvpict=imtweak(inpict,'husluv',cvec);

R1=cat(2,hsvpict,hsipict,hslpict);
R2=cat(2,ypppict,lchabpict,lchuvpict);
R3=cat(2,hsypict,huslabpict,husluvpict);
comparison=cat(1,R1,R2,R3);

subplot_tight(1,1,1);
imshow(255-comparison)
				
 
 

Example 3:
Do a 180 degree hue rotation of an image using HSV, HSI, HSL, YPP, LCH, HSY, and HuSL methods. Concatenate the images for easy comparison.

With HSV, HSI, and HSL, large hue rotations tend to cause value inversions and general rainbow nonsense. For HSY, LCH and HuSL, the local brightness of the image remains relatively unchanged despite the change. Note the brightness of the bottle caps, the board shadow, the green paint paint bottles, and the paper. As HuSL and HSY normalization results in a varying correspondence between normalized S and uniform C, their results aren't quite perfect, but as mentioned in the commentary, the normalization allows repeated operations without losing chroma information by truncation.

npict=imread('sources/blacklight2.jpg');

cvec=[0.5 1 1];
hsvpict=imtweak(inpict,'hsv',cvec);
hsipict=imtweak(inpict,'hsi',cvec);
hslpict=imtweak(inpict,'hsl',cvec);
ypppict=imtweak(inpict,'ypbpr',fliplr(cvec));
hsypict=imtweak(inpict,'hsy',cvec);
lchabpict=imtweak(inpict,'lchab',fliplr(cvec));
lchuvpict=imtweak(inpict,'lchuv',fliplr(cvec));
huslabpict=imtweak(inpict,'huslab',cvec);
husluvpict=imtweak(inpict,'husluv',cvec);

R1=cat(2,hsvpict,hsipict,hslpict);
R2=cat(2,ypppict,lchabpict,lchuvpict);
R3=cat(2,hsypict,huslabpict,husluvpict);
comparison=cat(1,R1,R2,R3);

subplot_tight(1,1,1);
imshow(255-comparison)
				
 
 

Example 4:
Perform a hue rotation using the biconic methods HuSLp and HSYp. Compared to HuSLp methods, HSYp has access to a greater fraction of its parent space and is able to render more saturated colors. This image is really an extreme use-case for these methods; an image with limited saturation range would show less influence from chroma limiting.

inpict=imread('sources/blacklight2.jpg');

cvec=[0.5 1 1];
A=imtweak(inpict,'huslab',cvec);
B=imtweak(inpict,'husluv',cvec);
C=imtweak(inpict,'hsy',cvec);
Ap=imtweak(inpict,'huslpab',cvec);
Bp=imtweak(inpict,'huslpuv',cvec);
Cp=imtweak(inpict,'hsyp',cvec);

R1=cat(2,A,Ap);
R2=cat(2,B,Bp);
R3=cat(2,C,Cp);
comparison=cat(1,R1,R2,R3);

subplot_tight(1,1,1);
imshow(255-comparison)
				
 
 

Example 5:
Perform successive hue rotations using LCHab and HuSLab methods. Concatenate only stripes from each transitional images to save some space. Do the same thing with YPbPr and HSY.

While HuSL/HSY methods don't perform hue rotations on a path of constant C, they do preserve the original image content by using relative S. Note how truncation causes chroma compression in the LCH method. The same compression occurs in YPbPr for the same reason, though if we recall the extent of HSYp as compared to HuSLp, it may come as no surprise that the compression has less impact in YPbPr than in LCHab/uv.

bg=imread('sources/blacklight2.jpg');

st=6;
lchset=bg;
huslset=bg;
yppset=bg;
hsyset=bg;
for k=1:st
    lchrot=imtweak(lchset(:,:,:,k),'lchab',[1 1 1/st]);
    huslrot=imtweak(huslset(:,:,:,k),'huslab',[1/st, 1, 1]);
    ypprot=imtweak(yppset(:,:,:,k),'ypbpr',[1 1 1/st]);
    hsyrot=imtweak(hsyset(:,:,:,k),'hsy',[1/st, 1, 1]);
    
    lchset=cat(4,lchset,lchrot);
    huslset=cat(4,huslset,huslrot);
    yppset=cat(4,yppset,ypprot);
    hsyset=cat(4,hsyset,hsyrot);
end

A=lchset(:,:,:,1);
B=huslset(:,:,:,1);
C=yppset(:,:,:,1);
D=hsyset(:,:,:,1);
s=size(bg);
for k=2:st
    h=round(s(1)/(st-1));
    mvec=min(((k-2)*h+1):((k-2)*h+h),s(1));
    A=cat(1,A,lchset(mvec,:,:,k));
    B=cat(1,B,huslset(mvec,:,:,k));
    C=cat(1,C,yppset(mvec,:,:,k));
    D=cat(1,D,hsyset(mvec,:,:,k));
end
A=cat(1,A,lchset(:,:,:,end));
B=cat(1,B,huslset(:,:,:,end));
C=cat(1,C,yppset(:,:,:,end));
D=cat(1,D,hsyset(:,:,:,end));
out1=cat(2,A,B);
out2=cat(2,C,D);

imshow(255-out1)
				
 
 
 

Example 6:
Use a dot mask to closely compare subtle differences in CIELAB and SRLAB2 LCH methods for a simple hue rotation

inpict=imread('sources/blacklight2.jpg');

cvec=[1 1 1/5];
ab1=imtweak(inpict,'lchab',cvec);
sr1=imtweak(inpict,'lchsr',cvec);
cvec=[1 1 2/5];
ab2=imtweak(inpict,'lchab',cvec);
sr2=imtweak(inpict,'lchsr',cvec);
cvec=[1 1 3/5];
ab3=imtweak(inpict,'lchab',cvec);
sr3=imtweak(inpict,'lchsr',cvec);
cvec=[1 1 4/5];
ab4=imtweak(inpict,'lchab',cvec);
sr4=imtweak(inpict,'lchsr',cvec);

bg=cat(2,cat(1,ab1,ab2),cat(1,ab3,ab4));
dots=cat(2,cat(1,sr1,sr2),cat(1,sr3,sr4));

s=size(bg);
V=eoline(true(s(1:2)),2,[20 40]);
H=eoline(true(s(1:2)),1,[20 40]);
mask=imdilate(xor(H,V),strel('square',8));
comparison=replacepixels(bg,dots,mask);

imshow(255-comparison)
				
 
 

Example 7:
Use RGB mode to amplify red channel, invert and attenuate blue channel

inpict=imread('sources/goat.jpg');

outpict=imtweak(inpict,'rgb',[1.1 1 -0.5]);

imshow(outpict)