This is a question about how to color correct an image using ImageMagick or similar.
We have an image with a CMYK swatch. The swatch was printed on non-glossy white card stock and we've measured the HSV of the Cyan (in real life) under pre-determined lighting conditions. We then include this swatch on the card stock in the foreground of other images we take. Because the other images all have different lighting conditions, we're not able to objectively identify the colors of the other objects in the image.
Is there a way, using ImageMagick or similar, to shift HSV values throughout the image, using Cyan as the base, so that the color or the other objects in the image reflect values similar to what they would have had, had they been shot in the same lighting conditions as the CMYK swatch?
In short, our goal is to be able to determine, with some accuracy, the HSV of, say, "Yellow" (which, without enough light can look orange or brown).
I've found a few articles that suggest techniques for doing similar things but nothing quite like what we're trying to do here.
Here are two trivial approaches using ImageMagick and Unix tools.
Input Image (from http://im.snibgo.com/dcrawwb.htm)
1) Get the reference cyan color from http://xritephoto.com/documents/literature/en/ColorData-1p_EN.pdf
cyan_ref="srgb(8,133,161)"
cyan_ref=`echo $cyan_ref | tr -cs "[0-9]*\n" " " | sed 's/^[ ]*//'`
echo "$cyan_ref"
8 133 161
Separate the r, g, and b values
cyan_ref_r=`echo $cyan_ref | cut -d\ -f1`
cyan_ref_g=`echo $cyan_ref | cut -d\ -f2`
cyan_ref_b=`echo $cyan_ref | cut -d\ -f3`
2) Crop a small rectangle from the image and get the average measured color for the cyan patch.
cyan_mea=`convert cyan_measure.png -scale 1x1! -format "[pixel:u.p{0,0}]" info:`
echo "cyan_mea=$cyan_mea"
srgb(2,147,187)
cyan_mea=`echo $cyan_mea | tr -cs "[0-9]*\n" " " | sed 's/^[ ]*//'`
echo "$cyan_mea"
2 147 187
Separate the r, g, and b values
cyan_mea_r=`echo $cyan_mea | cut -d\ -f1`
cyan_mea_g=`echo $cyan_mea | cut -d\ -f2`
cyan_mea_b=`echo $cyan_mea | cut -d\ -f3`
3) Compute the differences as percents (relative to 255)
red_pct=`convert xc: -format "%[fx:(cyan_ref_r-cyan_mea_r)/255]" info:`
green_pct=`convert xc: -format "%[fx:(cyan_ref_g-cyan_mea_g)/255]" info:`
blue_pct=`convert xc: -format "%[fx:(cyan_ref_b-cyan_mea_b)/255]" info:`
4) Convert the image:
convert ftc_typ_sm.jpg \
-channel r -evaluate add $red_pct% +channel \
-channel g -evaluate add $green_pct% +channel \
-channel b -evaluate add $blue_pct% +channel \
ftc_typ_sm_corrected_rgb.jpg
Now you have a corrected image and can measure any other color from the chart or image.
If your images are cmyk, then do the same for c, m, y, k or convert to RGB and do the above.
Alternately, you can do this in HCL colorspace:
1) Get the reference cyan color from http://xritephoto.com/documents/literature/en/ColorData-1p_EN.pdf and convert to HCL (or HSL or HSV etc).
cyan_ref="srgb(8,133,161)"
cyan_ref_hcl=`convert xc:"$cyan_ref" -colorspace HCL -format "%[pixel:u.p{0,0}]" info: | tr -cs "[0-9]*\n" " " | sed 's/^[ ]*//'`
echo "$cyan_ref_hcl"
191 60 39
Separate the h, c, l values
cyan_ref_h=`echo "$cyan_ref_hcl" | cut -d\ -f1`
cyan_ref_c=`echo "$cyan_ref_hcl" | cut -d\ -f2`
cyan_ref_l=`echo "$cyan_ref_hcl" | cut -d\ -f3`
2) Measure the cyan swatch and convert the average to HCL
cyan_mea=`convert cyan_measure.png -scale 1x1! -format "%[pixel:u.p{0,0}]" info:`
echo "$cyan_mea"
srgb(2,147,187)
cyan_mea_hcl=`convert xc:"$cyan_mea" -colorspace HCL -format "%[pixel:u.p{0,0}]" info: | tr -cs "[0-9]*\n" " " | sed 's/^[ ]*//'`
echo "$cyan_mea_hcl"
193 73 42
Separate the h, c, l values
cyan_mea_h=`echo "$cyan_mea_hcl" | cut -d\ -f1`
cyan_mea_c=`echo "$cyan_mea_hcl" | cut -d\ -f2`
cyan_mea_l=`echo "$cyan_mea_hcl" | cut -d\ -f3`
3) Compute the differences and change to values suitable for -modulate (see http://www.imagemagick.org/script/command-line-options.php#modulate)
cyan_h_diff=$((cyan_ref_h-cyan_mea_h))
cyan_c_diff=$((cyan_ref_c-cyan_mea_c))
cyan_l_diff=$((cyan_ref_l-cyan_mea_l))
echo "cyan_h_diff=$cyan_h_diff; cyan_c_diff=$cyan_c_diff; cyan_l_diff=$cyan_l_diff;"
cyan_h_diff=-2; cyan_c_diff=-13; cyan_l_diff=-3;
modh=`convert xc: -format "%[fx:100+$cyan_h_diff*200/360]" info:`
modc=$((100+cyan_c_diff))
modl=$((100+cyan_l_diff))
echo "modh=$modh; modc=$modc; modl=$modl"
modh=98.8889; modc=87; modl=97
4) Process the image
convert ftc_typ_sm.jpg -define modulate:colorspace=HCL -modulate $modh,$modc,$modl ftc_typ_sm_corrected_hcl.jpg
For more accurate approaches:
1) Do the RGB method for all swatches and compute the average R, G, B differences.
2) Do the HCL method and compute the average H, C, L differences
3) Do same but compute a lookup table for each of the red, green and blue (or hue, chroma, lightness) channels from the pairs of input and output values from each color patch in the image and the reference table.