Assuming that one image has been transformed to another by "-level", what were the parameters?
The problem might occur because we have used "-contrast-stretch", and want to know the equivalent "-level".
ASIDE. This page is one of a series that address the question: "What colour transformation makes this image look like that image?"
The pages in that series, roughly from simple to complex, are:
We assume one image has been transformed to another by a "-level" operation, or possibly three operations (one for each RGB channel), or "contrast-stretch". We have the input and result images. The task is to find the two percentage parameters of each "-level".
The "-level" operation is linear, so a pair of input pixels, and the corresponding result pixels, are sufficient to define the parameters provided the pair of pixels are different in all channels, and clipping has not occurred.
By default, the script will use pixels at the top-left and bottom-right corners. The user can choose different coordinates. If the input pixels values are integer, for good precision we should choose a pair that is distant within the colour-cube; basically, choose a light pixel and a dark pixel, but not black or white in the result image.
[What if +level was used?]
[Linear regression]
[cf Gain and Bias]
Suppose we had "-level L1,L2" where L1 and L2 are proportions of QuantumRange, [0..1]. The linear transformation is:
vout = (vin-L1) / (L2-L1)
... where vin and vout are [0..1].
In each pair of pixels, we number them 0 and 1. So we have two simultaneous equations:
vout0 = (vin0-L1) / (L2-L1) = vin0/(L2-L1) - L1/(L2-L1) vout1 = (vin1-L1) / (L2-L1) = vin1/(L2-L1) - L1/(L2-L1)
By subtraction:
vout0-vout1 = vin0/(L2-L1) - vin1/(L2-L1) = (vin0-vin1) / (L2-L1)
So:
L2-L1 = (vin0-vin1) / (vout0-vout1) L1 = vin0 - vout0 * (L2-L1) L2 = (L2-L1) + L1
Thus, we can calculate L1 and L2 for each channel.
The script whatLevel.bat does the work.
toes.png |
|
Increase contrast slightly: %IMG7%magick ^ toes.png ^ -level 5,95%% ^ wl_samp1.png |
Calculate the parameters:
call %PICTBAT%whatLevel toes.png wl_samp1.png wl_samp1
List the parameters:
set wl_samp1
wl_samp1_L1_B=5.00077314512755 wl_samp1_L1_G=5.00007629511308 wl_samp1_L1_R=5.01276829756772 wl_samp1_L2_B=94.9977015776046 wl_samp1_L2_G=95.0000762951048 wl_samp1_L2_R=94.9790008108331 wl_samp1_strLevel=-channel R -level 5.01276829756772x94.9790008108331% -channel G -level 5.00007629511308x95.0000762951048% -channel B -level 5.00077314512755x94.9977015776046% +channel
As we might hope, the parameters are more or less the same for the three channels, and are more or less correct.
For convenience, the script also creates an environment variable that can apply the "-level" commands, like this:
%IMG7%magick ^ toes.png ^ %wl_samp1_strLevel% ^ wl_appd.png |
If we want only one "-level", we can set wlPreProc to convert to grayscale, then back to sRGB so we have three channels:
set wlPreProc=-colorspace Gray -colorspace sRGB call %PICTBAT%whatLevel toes.png wl_samp1.png wl_samp1a set wlPreProc=
List the parameters:
set wl_samp1a
wl_samp1a_L1_B=5.01453560865443 wl_samp1a_L1_G=5.01453560865443 wl_samp1a_L1_R=5.01453560865443 wl_samp1a_L2_B=94.9791519744924 wl_samp1a_L2_G=94.9791519744924 wl_samp1a_L2_R=94.9791519744924 wl_samp1a_strLevel=-channel R -level 5.01453560865443x94.9791519744924% -channel G -level 5.01453560865443x94.9791519744924% -channel B -level 5.01453560865443x94.9791519744924% +channel
The parameters are the same for all channels, so we could use any of them.
As a test, we find what "-level" transforms an image to itself:
call %PICTBAT%whatLevel toes.png toes.png wl_same
List the parameters:
set wl_same
wl_same_L1_B=0 wl_same_L1_G=0 wl_same_L1_R=0 wl_same_L2_B=100 wl_same_L2_G=100 wl_same_L2_R=100 wl_same_strLevel=-channel R -level 0x100% -channel G -level 0x100% -channel B -level 0x100% +channel
For another example, we use a negative slope:
Negative slope: %IMG7%magick ^ toes.png ^ -level 95,5%% ^ wl_neg.png |
Calculate the parameters:
call %PICTBAT%whatLevel toes.png wl_neg.png wl_neg
List the parameters:
set wl_neg
wl_neg_L1_B=94.9977015776045 wl_neg_L1_G=95.0000762951082 wl_neg_L1_R=95.0064931851386 wl_neg_L2_B=5.0007731451275 wl_neg_L2_G=5.0000762951105 wl_neg_L2_R=4.9968406754855 wl_neg_strLevel=-channel R -level 95.0064931851386x4.9968406754855% -channel G -level 95.0000762951082x5.0000762951105% -channel B -level 94.9977015776045x5.0007731451275% +channel
If the transformation was actually -level, then just two pixels will find the parameters. But if the transformation was more complex, two arbitrary pixels will probably not find the best fit.
The script whatLevelP.bat finds the parameters for "+level-colors" or "+level".
Since the first version of this page, IM has acquired the ftxt: coder, which simplifies the process.
Suppose we had "+level L1,L2" where L1 and L2 are proportions of QuantumRange, [0..1]. The linear transformation is:
vout = L1 + vin * (L2-L1)
... where vin and vout are [0..1].
In each pair of pixels, we number them 0 and 1. So we have two simultaneous equations:
vout0 = L1 + vin0 * (L2-L1) vout1 = L1 + vin1 * (L2-L1)
By subtraction:
vout0 - vout1 = (vin0 - vin1) * (L2-L1)
So:
(L2-L1) = (vout0 - vout1) / (vin0 - vin1) L1 = vout0 - vin0 * (L2-L1) L2 = (L2-L1) + L1
Thus, we can calculate L1 and L2 for each channel.
The script whatLevelP.bat does the work. It writes two environment variables that can be used in "+level-colors". It could be modified to write six environment variables, to use in a "+level" for each channel.
The scripts whatLevel.bat and whatLevelP.bat, by default, use pixel values from the top-left and bottom-right corners of the images. If these pixels have integer values that are close together, small quantization errors can cause a large error in the calculated slopes. The script twoNotClipped.bat chooses pixel coordinates to minimize this problem.
See Wikipedia: Ordinary least squares: Simple linear regression model.
This models the transformation from input pixel values X to output pixel values Y as:
Y = intercept + slope * X
... where:
slope = nPixels * sumXY - sigX * sigY nPixels * sumXsquared - sigX * sigX intercept = meanY - slope * meanX
where, taking X and Y as zero to one:
The slope equation simplifies to:
slope = nPixels*nPixels * (mean(X*Y) - meanX*meanY) nPixels*nPixels * (mean(X*X) - meanX*meanX) = mean(X*Y) - meanX*meanY mean(X*X) - meanX*meanX
The script linReg2img.bat calculates the slope and intercept for three channels.
call %PICTBAT%linReg2img toes.png wl_samp1.png wl_lr1
List the parameters:
set wl_lr1
wl_lr1_bias_B=-0.0555442404345006 wl_lr1_bias_G=-0.0555539263370718 wl_lr1_bias_R=-0.0546464913786526 wl_lr1_gain_B=1.11108997100786 wl_lr1_gain_G=1.11110952162966 wl_lr1_gain_R=1.10916304264897
We could make all Y pixels that might have been clipped transparent.
call %PICTBAT%gbToL1L2 wl_lr1
set wl_lr1
wl_lr1_bias_B=-0.0555442404345006 wl_lr1_bias_G=-0.0555539263370718 wl_lr1_bias_R=-0.0546464913786526 wl_lr1_gain_B=1.11108997100786 wl_lr1_gain_G=1.11110952162966 wl_lr1_gain_R=1.10916304264897 wl_lr1_L1_B=4.99907675200388 wl_lr1_L1_G=4.99986052280346 wl_lr1_L1_R=4.92682223238727 wl_lr1_L2_B=95.0007891329471 wl_lr1_L2_G=94.9999892709852 wl_lr1_L2_R=95.0848929170848
call %PICTBAT%gbToL3pL4p wl_lr1
set wl_lr1
wl_lr1_bias_B=-0.0555442404345006 wl_lr1_bias_G=-0.0555539263370718 wl_lr1_bias_R=-0.0546464913786526 wl_lr1_gain_B=1.11108997100786 wl_lr1_gain_G=1.11110952162966 wl_lr1_gain_R=1.10916304264897 wl_lr1_L1_B=4.99907675200388 wl_lr1_L1_G=4.99986052280346 wl_lr1_L1_R=4.92682223238727 wl_lr1_L2_B=95.0007891329471 wl_lr1_L2_G=94.9999892709852 wl_lr1_L2_R=95.0848929170848 wl_lr1_L3p_B=-5.55442404345006 wl_lr1_L3p_G=-5.55539263370718 wl_lr1_L3p_R=-5.46464913786526 wl_lr1_L4p_B=105.554573057336 wl_lr1_L4p_G=105.555559529259 wl_lr1_L4p_R=105.451655127032
call %PICTBAT%L1L2toGb wl_lr1
set wl_lr1
wl_lr1_bias_B=-0.0555442404345006 wl_lr1_bias_Bx=-0.0555442404345006 wl_lr1_bias_G=-0.0555539263370718 wl_lr1_bias_Gx=-0.0555539263370717 wl_lr1_bias_R=-0.0546464913786526 wl_lr1_bias_Rx=-0.0546464913786525 wl_lr1_gain_B=1.11108997100786 wl_lr1_gain_Bx=1.11108997100786 wl_lr1_gain_G=1.11110952162966 wl_lr1_gain_Gx=1.11110952162966 wl_lr1_gain_R=1.10916304264897 wl_lr1_gain_Rx=1.10916304264897 wl_lr1_L1_B=4.99907675200388 wl_lr1_L1_G=4.99986052280346 wl_lr1_L1_R=4.92682223238727 wl_lr1_L2_B=95.0007891329471 wl_lr1_L2_G=94.9999892709852 wl_lr1_L2_R=95.0848929170848 wl_lr1_L3p_B=-5.55442404345006 wl_lr1_L3p_G=-5.55539263370718 wl_lr1_L3p_R=-5.46464913786526 wl_lr1_L4p_B=105.554573057336 wl_lr1_L4p_G=105.555559529259 wl_lr1_L4p_R=105.451655127032
call %PICTBAT%L3pL4ptoGb wl_lr1
set wl_lr1
wl_lr1_bias_B=-0.0555442404345006 wl_lr1_bias_Bx=-0.0555442404345006 wl_lr1_bias_By=-0.0555442404345006 wl_lr1_bias_G=-0.0555539263370718 wl_lr1_bias_Gx=-0.0555539263370717 wl_lr1_bias_Gy=-0.0555539263370718 wl_lr1_bias_R=-0.0546464913786526 wl_lr1_bias_Rx=-0.0546464913786525 wl_lr1_bias_Ry=-0.0546464913786526 wl_lr1_gain_B=1.11108997100786 wl_lr1_gain_Bx=1.11108997100786 wl_lr1_gain_G=1.11110952162966 wl_lr1_gain_Gx=1.11110952162966 wl_lr1_gain_R=1.10916304264897 wl_lr1_gain_Rx=1.10916304264897 wl_lr1_L1_B=4.99907675200388 wl_lr1_L1_G=4.99986052280346 wl_lr1_L1_R=4.92682223238727 wl_lr1_L2_B=95.0007891329471 wl_lr1_L2_G=94.9999892709852 wl_lr1_L2_R=95.0848929170848 wl_lr1_L3p_B=-5.55442404345006 wl_lr1_L3p_G=-5.55539263370718 wl_lr1_L3p_R=-5.46464913786526 wl_lr1_L4p_B=105.554573057336 wl_lr1_L4p_G=105.555559529259 wl_lr1_L4p_R=105.451655127032
For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.
rem Given image %1 was transformed by "-level L1xL2", rem and we have the same-size result image %2, rem what are the parameters L1 and L2? rem Write parameters to environment variables prefixed with %3. rem %4 quoted x,y coords of pixel in both images. rem %5 quoted x,y coords of another pixel in both images. @rem @rem Also uses: @rem wlPreProc Pre-process for both inputs. @rem rem We compare corresponding pixels in the two images. rem The pixels must be different, and must not have been clamped. @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 wl set In1=%1 set In2=%2 set Coords1=%4 if [%Coords1%]==[.] set Coords1= if [%Coords1%]==[] set Coords1="0,0" set Coords2=%5 if [%Coords2%]==[.] set Coords2= if [%Coords2%]==[] set Coords2="-1,-1" call %UTIL%\parseCommaList %Coords1% Cds1 Cds1 if not %Cds1%==2 ( echo %0: Coords1 [%Coords1%] should be two comma-separated numbers. exit /B 1 ) call %UTIL%\parseCommaList %Coords2% Cds2 Cds2 if not %Cds2%==2 ( echo %0: Coords2 [%Coords2%] should be two comma-separated numbers. exit /B 1 ) set X1=%Cds1[0]% set Y1=%Cds1[1]% set X2=%Cds2[0]% set Y2=%Cds1[1]% for /F "usebackq" %%L in (`%IMG7%magick ^ -precision 15 ^ %In1% %In2% ^ %wlPreProc% ^ ^( -clone 0-1 ^ -crop "1x1+%%[fx:mod(%X1%,w)]+%%[fx:mod(%Y1%,h)]" +repage ^ ^( -clone 0 ^ -format "vin0r=%%[fx:mean.r]\nvin0g=%%[fx:mean.g]\nvin0b=%%[fx:mean.b]\n" -write info: ^ +delete ^ ^) ^ ^( -clone 1 ^ -format "vout0r=%%[fx:mean.r]\nvout0g=%%[fx:mean.g]\nvout0b=%%[fx:mean.b]\n" -write info: ^ +delete ^ ^) ^ -delete 0--1 ^ ^) ^ ^( -clone 0-1 ^ -crop "1x1+%%[fx:mod(%X2%,w)]+%%[fx:mod(%Y2%,h)]" +repage ^ ^( -clone 0 ^ -format "vin1r=%%[fx:mean.r]\nvin1g=%%[fx:mean.g]\nvin1b=%%[fx:mean.b]\n" -write info: ^ +delete ^ ^) ^ ^( -clone 1 ^ -format "vout1r=%%[fx:mean.r]\nvout1g=%%[fx:mean.g]\nvout1b=%%[fx:mean.b]\n" -write info: ^ +delete ^ ^) ^ -delete 0--1 ^ ^) ^ null:`) do set %%L echo %0: vin0: %vin0r% %vin0g% %vin0b% echo %0: vout0: %vout0r% %vout0g% %vout0b% echo %0: vin1: %vin1r% %vin1g% %vin1b% echo %0: vout1: %vout1r% %vout1g% %vout1b% set FMT=^ vindr=%%[fx:(%vin0r%-(%vin1r%))]\n^ vindg=%%[fx:(%vin0g%-(%vin1g%))]\n^ vindb=%%[fx:(%vin0b%-(%vin1b%))]\n^ voutdr=%%[fx:(%vout0r%-(%vout1r%))]\n^ voutdg=%%[fx:(%vout0g%-(%vout1g%))]\n^ voutdb=%%[fx:(%vout0b%-(%vout1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: vind: %vindr% %vindg% %vindb% echo %0: voutd: %voutdr% %voutdg% %voutdb% if %voutdr%==0 ( echo voutdr is zero exit /B 1 ) if %voutdg%==0 ( echo voutdg is zero exit /B 1 ) if %voutdb%==0 ( echo voutdb is zero exit /B 1 ) set FMT=^ L2mL1r=%%[fx:100*(%vin0r%-(%vin1r%))/(%vout0r%-(%vout1r%))]\n^ L2mL1g=%%[fx:100*(%vin0g%-(%vin1g%))/(%vout0g%-(%vout1g%))]\n^ L2mL1b=%%[fx:100*(%vin0b%-(%vin1b%))/(%vout0b%-(%vout1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: L2mL1: %L2mL1r% %L2mL1g% %L2mL1b% set FMT=^ L1r=%%[fx:(%vin0r%*100-(%vout0r%)*(%L2mL1r%))]\n^ L1g=%%[fx:(%vin0g%*100-(%vout0g%)*(%L2mL1g%))]\n^ L1b=%%[fx:(%vin0b%*100-(%vout0b%)*(%L2mL1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: L1: %L1r% %L1g% %L1b% set FMT=^ L2r=%%[fx:(%L2mL1r%+(%L1r%))]\n^ L2g=%%[fx:(%L2mL1g%+(%L1g%))]\n^ L2b=%%[fx:(%L2mL1b%+(%L1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: L2: %L2r% %L2g% %L2b% set strLevel=^ -channel R -level %L1r%x%L2r%%% ^ -channel G -level %L1g%x%L2g%%% ^ -channel B -level %L1b%x%L2b%%% ^ +channel echo %0: strLevel: %strLevel% rem Verify: if we level with these numbers, do we get the expected result? %IMG7%magick ^ %In1% ^ %strLevel% ^ %In2% ^ -metric RMSE ^ -format "%%[distortion]\n" -compare ^ info: call echoRestore @endlocal & set %3_L1_R=%L1r%& set %3_L1_G=%L1g%& set %3_L1_B=%L1b%&^ set %3_L2_R=%L2r%& set %3_L2_G=%L2g%& set %3_L2_B=%L2b%&^ set %3_strLevel=%strLevel%
rem Given image %1 was transformed by "+level L1xL2", rem and we have the same-size result image %2, rem what are the parameters L1 and L2? rem Write parameters to environment variables prefixed with %3. rem %4 quoted x,y coords of pixel in both images. rem %5 quoted x,y coords of another pixel in both images. @rem @rem Also uses: @rem wlPreProc Pre-process for both inputs. @rem rem We compare corresponding pixels in the two images. rem The pixels must be different, and must not have been clamped. @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion rem @call echoOffSave call %PICTBAT%setInOut %1 wl set In1=%1 set In2=%2 set Coords1=%4 if [%Coords1%]==[.] set Coords1= if [%Coords1%]==[] set Coords1="0,0" set Coords2=%5 if [%Coords2%]==[.] set Coords2= if [%Coords2%]==[] set Coords2="-1,-1" call %UTIL%\parseCommaList %Coords1% Cds1 Cds1 if not %Cds1%==2 ( echo %0: Coords1 [%Coords1%] should be two comma-separated numbers. exit /B 1 ) call %UTIL%\parseCommaList %Coords2% Cds2 Cds2 if not %Cds2%==2 ( echo %0: Coords2 [%Coords2%] should be two comma-separated numbers. exit /B 1 ) set X1=%Cds1[0]% set Y1=%Cds1[1]% set X2=%Cds2[0]% set Y2=%Cds1[1]% for /F "usebackq" %%L in (`%IMG7%magick ^ -precision 15 ^ -define "compose:clamp=off" ^ %In1% %In2% ^ %wlPreProc% ^ ^( -clone 0-1 ^ -crop "1x1+%%[fx:mod(%X1%,w)]+%%[fx:mod(%Y1%,h)]" +repage ^ ^( -clone 0 ^ -define ftxt:format^="vin0=\s\n" -write ftxt: ^ -write mpr:vin0 ^ +delete ^ ^) ^ ^( -clone 1 ^ -define ftxt:format^="vout0=\s\n" -write ftxt: ^ -write mpr:vout0 ^ +delete ^ ^) ^ -delete 0--1 ^ ^) ^ ^( -clone 0-1 ^ -crop "1x1+%%[fx:mod(%X2%,w)]+%%[fx:mod(%Y2%,h)]" +repage ^ ^( -clone 0 ^ -define ftxt:format^="vin1=\s\n" -write ftxt: ^ -write mpr:vin1 ^ +delete ^ ^) ^ ^( -clone 1 ^ -define ftxt:format^="vout1=\s\n" -write ftxt: ^ -write mpr:vout1 ^ +delete ^ ^) ^ -delete 0--1 ^ ^) ^ -delete 0--1 ^ mpr:vout0 mpr:vout1 ^ -compose MinusSrc -composite ^ ^( mpr:vin0 mpr:vin1 ^ -compose MinusSrc -composite ^ ^) ^ -compose DivideSrc -composite ^ -define ftxt:format^="L2mL1=\s\n" -write ftxt: ^ +write mpr:L2mL1 ^ mpr:vin0 ^ -compose Multiply -composite ^ mpr:vout0 ^ -compose MinusDst -composite ^ -define ftxt:format^="L1=\s\n" -write ftxt: ^ +write mpr:L1 ^ mpr:L2mL1 ^ -compose Plus -composite ^ -define ftxt:format^="L2=\s\n" -write ftxt: ^ null:`) do set %%L echo %0: vin0: %vin0% echo %0: vout0: %vout0% echo %0: vin1: %vin1% echo %0: vout1: %vout1% exit /B 0 set FMT=^ vindr=%%[fx:(%vin0r%-(%vin1r%))]\n^ vindg=%%[fx:(%vin0g%-(%vin1g%))]\n^ vindb=%%[fx:(%vin0b%-(%vin1b%))]\n^ voutdr=%%[fx:(%vout0r%-(%vout1r%))]\n^ voutdg=%%[fx:(%vout0g%-(%vout1g%))]\n^ voutdb=%%[fx:(%vout0b%-(%vout1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: vind: %vindr% %vindg% %vindb% echo %0: voutd: %voutdr% %voutdg% %voutdb% if %voutdr%==0 ( echo voutdr is zero exit /B 1 ) if %voutdg%==0 ( echo voutdg is zero exit /B 1 ) if %voutdb%==0 ( echo voutdb is zero exit /B 1 ) set FMT=^ L2mL1r=%%[fx:100*(%vin0r%-(%vin1r%))/(%vout0r%-(%vout1r%))]\n^ L2mL1g=%%[fx:100*(%vin0g%-(%vin1g%))/(%vout0g%-(%vout1g%))]\n^ L2mL1b=%%[fx:100*(%vin0b%-(%vin1b%))/(%vout0b%-(%vout1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: L2mL1: %L2mL1r% %L2mL1g% %L2mL1b% set FMT=^ L1r=%%[fx:(%vin0r%*100-(%vout0r%)*(%L2mL1r%))]\n^ L1g=%%[fx:(%vin0g%*100-(%vout0g%)*(%L2mL1g%))]\n^ L1b=%%[fx:(%vin0b%*100-(%vout0b%)*(%L2mL1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: L1: %L1r% %L1g% %L1b% set FMT=^ L2r=%%[fx:(%L2mL1r%+(%L1r%))]\n^ L2g=%%[fx:(%L2mL1g%+(%L1g%))]\n^ L2b=%%[fx:(%L2mL1b%+(%L1b%))]\n for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 15 ^ -format "%FMT%" ^ xc:`) do set %%L echo %0: L2: %L2r% %L2g% %L2b% set strLevel=^ -channel R -level %L1r%x%L2r%%% ^ -channel G -level %L1g%x%L2g%%% ^ -channel B -level %L1b%x%L2b%%% ^ +channel echo %0: strLevel: %strLevel% rem Verify: if we level with these numbers, do we get the expected result? %IMG7%magick ^ %In1% ^ %strLevel% ^ %In2% ^ -metric RMSE ^ -format "%%[distortion]\n" -compare ^ info: call echoRestore @endlocal & set %3_L1_R=%L1r%& set %3_L1_G=%L1g%& set %3_L1_B=%L1b%&^ set %3_L2_R=%L2r%& set %3_L2_G=%L2g%& set %3_L2_B=%L2b%&^ set %3_strLevel=%strLevel%
rem Linear regression of 2 images. rem %1 image: independent variable rem %2 image: dependent variable rem %3 prefix for output environment variables. Returns %3_gain_R, %3_bias_R etc. @rem @rem Images must be same size. (Script doesn't check this.) @rem @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @call echoOffSave for /F "usebackq" %%L in (`%IMG7%magick ^ %1 ^ %2 ^ -precision 15 ^ -define "compose:clamp=off" ^ ^( -clone 0 ^ -scale "1x1^!" ^ -write mpr:MnX ^ -evaluate Pow 2 ^ -write mpr:MnXMnX ^ +delete ^ ^) ^ ^( -clone 0 ^ -evaluate Pow 2 ^ -scale "1x1^!" ^ -write mpr:MnXX ^ +delete ^ ^) ^ ^( -clone 1 ^ -scale "1x1^!" ^ -write mpr:MnY ^ +delete ^ ^) ^ ^( -clone 0-1 ^ -compose Multiply -composite ^ -scale "1x1^!" ^ -write mpr:MnXY ^ +delete ^ ^) ^ -delete 0-1 ^ ^( mpr:MnX mpr:MnY ^ -compose Multiply -composite ^ mpr:MnXY ^ -compose Mathematics -define "compose:args=0,1,-1,0" -composite ^ -write mpr:NUMER ^ +delete ^ ^) ^ ^( mpr:MnXX mpr:MnXMnX ^ -compose Mathematics -define "compose:args=0,-1,1,0" -composite ^ mpr:NUMER ^ -compose DivideDst -composite ^ -write mpr:SLOPE ^ -format "%3_gain_R=%%[fx:mean.r]\n%3_gain_G=%%[fx:mean.g]\n%3_gain_B=%%[fx:mean.b]\n" ^ -write info: ^ +delete ^ ^) ^ ^( mpr:SLOPE mpr:MnX ^ -compose Multiply -composite ^ mpr:MnY ^ -compose Mathematics -define "compose:args=0,1,-1,0" -composite ^ -write mpr:INTR ^ -format "%3_bias_R=%%[fx:mean.r]\n%3_bias_G=%%[fx:mean.g]\n%3_bias_B=%%[fx:mean.b]\n" ^ -write info: ^ +delete ^ ^) ^ NULL:`) do set %%L call echoRestore
rem From input image %1 rem find two non-clipped pixels that are distant colorimetrically. rem rem Specifically: find the pixel that has the highest channel closest to 90%, rem and the lowest channel closest to 10%. setlocal enabledelayedexpansion set loX= for /F "usebackq tokens=1,4,5 delims=:(), " %%A in (`%IMG7%magick ^ %1 ^ ^( +clone ^ -channel RGB -separate +channel -evaluate-sequence Min ^ -range-threshold "0,10,10,100%%" ^ -define "identify:locate=maximum" -define "identify:limit=1" ^ +write info: ^ +delete ^ ^) ^ -channel RGB -separate +channel -evaluate-sequence Max ^ -range-threshold "0,90,90,100%%" ^ -define "identify:locate=maximum" -define "identify:limit=1" ^ info:`) do ( if /I "%%A"=="Red" ( echo %%A %%B %%C if "!loX!"=="" ( set loX=%%B set loY=%%C ) else ( set hiX=%%B set hiY=%%C ) ) ) echo loX=%loX% loY=%loY% hiX=%hiX% hiY=%hiY% endlocal & set loX=%loX%& set loY=%loY%& set hiX=%hiX%& set hiY=%hiY%
All images on this page were created by the commands shown, using:
%IMG7%magick -version
Version: ImageMagick 7.1.1-15 Q16-HDRI x64 a0a5f3d:20230730 https://imagemagick.org Copyright: (C) 1999 ImageMagick Studio LLC License: https://imagemagick.org/script/license.php Features: Cipher DPC HDRI OpenCL OpenMP(2.0) Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib Compiler: Visual Studio 2022 (193532217)
To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.
Source file for this web page is whatlev.h1. To re-create this web page, execute "procH1 whatlev".
This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.
Anyone is permitted to re-publish this page, but only for non-commercial use.
Anyone is permitted to link to this page, including for commercial use.
Page version v1.0 7-August-2020.
Page created 23-Oct-2023 15:26:13.
Copyright © 2023 Alan Gibson.