snibgo's ImageMagick pages

What scale?

Given one image that could be another image rescaled, what is the best scale factor?

See also the related page What rotation?.

The problem is solved by trial and error, with a twist: we construct a weird transformation of each image, then use IM's "subimage-search" to find the answer.

This is a sub-problem of the more general problem: "What areas in image A match what areas in image B?"

Sample inputs

We crop a photograph and make three versions:

  1. No resize.
  2. Enlarged to 120%.
  3. Reduced to 80%.
set wsDEBUG=1

%IM%convert ^
  \pictures\20140430\GOPR0166.JPG ^
  +depth ^
  -crop 600x400+2164+2240 +repage ^
  -gravity Center ^
  ( -clone 0 ^
    -crop 300x200+0+0 +repage ^
    -write ws_src1.png ^
    +delete ) ^
  ( -clone 0 ^
    -resize 120%% ^
    -crop 300x200+0+0 +repage ^
    -write ws_src2.png ^
    +delete ) ^
  ( -clone 0 ^
    -resize 80%% ^
    -crop 300x200+0+0 +repage ^
    -write ws_src3.png ^
    +delete ) ^
  NULL:
ws_src1.pngjpg ws_src2.pngjpg ws_src3.pngjpg

We will find what scaling factors applied to the first image would make each of the other two. If the method works, we will get 120% and 80%.

The method

The images must be the same size. We assume the images with respect to each other are centred and not rotated. (The method can be adapted to allow for rotations. See What rotation and scale?.)

Suppose we crop both input images to the central row, so we have two images, both one pixel high. They won't be exactly equal, because one is a scaled version of the other.

We can rescale the central row by a number of different factors, and append these rows vertically. Now we have a 2-dimensional image that represents the central row of the first image at different scales. If we search for the central row of the second within this 2-D image, the best match will tell us the scale factor.

This would find the best scale for just the central rows, but these might contain weird data that gave a spurious result. We could take every single row and append them together, creating a very wide image that was one pixel high. That should be very accurate but would take a long time and the image would be huge.

The script makes an average of all the rows, by -scale "x1^!". In case this data is weird, it also takes the average of all the columns (by scaling and rotating), and appends this to the average of the rows. The result is necessarily blurred, so it also appends the central row and central column.

By doing this many times, by default 100 times, we get an image that is 2*(W+H) pixels wide and 100 pixels high. This represents the first image at 100 different scales.

The second image is given the same initial treatment but not at different scales. This is 2*(W+H) pixels wide and one pixel high.

Now we search for the second with the first, and the Y-offset gives us the scale. The images are the same width, so the search is fast.

Finally, we obtain a score by scaling the first image, cropping the largest image to the size of the smallest, and comparing.

Using the script

call %PICTBAT%whatScale ws_src1.png ws_src2.png
if ERRORLEVEL 1 exit /B 1

echo SCALE=%wsSCALE% FACT=%wsFACT% SCORE_SUB=%wsSCORE_SUB% DODGY=%wsDODGY% 
SCALE=1.20411217 FACT=1.01104669 SCORE_SUB=0.0198597 DODGY=0 
call %PICTBAT%whatScale ws_src1.png ws_src3.png
if ERRORLEVEL 1 exit /B 1

echo SCALE=%wsSCALE% FACT=%wsFACT% SCORE_SUB=%wsSCORE_SUB% DODGY=%wsDODGY% 
SCALE=0.801921958 FACT=1.01104669 SCORE_SUB=0.0180756 DODGY=0 

The scale results are very close to the expected values, better than 1%. The "wsFACT" number is an error boundary; the true best result should be between wsSCALE/wsFACT and wsSCALE*wsFACT.

If the returned value wsDODGY was 1, this would mean the best result was at one end of the searched range, suggesting that the true best result was outside the searched range.

If greater precision is required, the script can be called repeatedly with smaller gaps between the tested limits by setting argument 3 to again.

call %PICTBAT%whatScale ws_src1.png ws_src3.png again
if ERRORLEVEL 1 exit /B 1

echo SCALE=%wsSCALE% FACT=%wsFACT% SCORE_SUB=%wsSCORE_SUB% DODGY=%wsDODGY% 
SCALE=0.799458895 FACT=1.00043954 SCORE_SUB=0.00982374 DODGY=0 

The result isn't within the FACT limits. The "again" mechanism searches within the square of FACT. Let's try another "again":

call %PICTBAT%whatScale ws_src1.png ws_src3.png again
if ERRORLEVEL 1 exit /B 1

echo SCALE=%wsSCALE% FACT=%wsFACT% SCORE_SUB=%wsSCORE_SUB% DODGY=%wsDODGY% 
SCALE=0.799458982 FACT=1.00001758 SCORE_SUB=0.00982352 DODGY=0 

As the images are smaller than 1000x1000 pixels, we shouldn't expect a precision or accuracy better than about 0.001.

By default, the script tries 100 scales. It may be quicker to first try just 10, then 20 within the two limits.

These are images that were compared:

Multi-scale version of the first image,
with a blue line showing where the second image was found,
and a red line showing where the third image was found:

%IM%convert ^
  %TEMP%\ws_src1_ws_0.5_1.5_100.miff ^
  -draw "fill Blue rectangle 0,79 999,79" ^
  -draw "fill Red  rectangle 0,42 999,42" ^
  ws_comp1.png
ws_comp1.pngjpg

The second image, scaled vertically so we can see it:

%IM%convert ^
  %TEMP%\ws_src2_ws.miff ^
  -scale "x50^!" ^
  ws_comp2.png
ws_comp2.pngjpg

The third image, scaled vertically so we can see it:

%IM%convert ^
  %TEMP%\ws_src3_ws.miff ^
  -scale "x50^!" ^
  ws_comp3.png
ws_comp3.pngjpg

The multi-scale version of the first image suggests a quick-and-dirty improvement: this could be constructed by making the top and bottom rows and interpolating between them with "-morph". This would give a linear interpolation between the scales instead of a constant ratio.

The images also show that the left halves (which represent the entire image) have substantially less contrast than the right halves (which represent just the central row and column). This may give too much weight to the central row and column, and it might be better to reduce the contrast of these.

It might be better if virtual pixels were made transparent, and we compared with RMSE that ignored transparent pixels.

Unlike What rotation? and What rotation and scale?, all the pixels are used to find the solution.

The debugging images show:

ws_ws_src1_ws_src2_dbg.pngjpg ws_ws_src1_ws_src3_dbg.pngjpg

We can also test the identity case, ie match an image against itself:

call %PICTBAT%whatScale ws_src1.png ws_src1.png
if ERRORLEVEL 1 exit /B 1

echo SCALE=%wsSCALE% FACT=%wsFACT% SCORE_SUB=%wsSCORE_SUB% DODGY=%wsDODGY% 
SCALE=0.998978955 FACT=1.01104669 SCORE_SUB=0.00828582 DODGY=0 
call %PICTBAT%whatScale ws_src1.png ws_src1.png again
if ERRORLEVEL 1 exit /B 1

echo SCALE=%wsSCALE% FACT=%wsFACT% SCORE_SUB=%wsSCORE_SUB% DODGY=%wsDODGY% 
SCALE=0.999857259 FACT=1.00043954 SCORE_SUB=0.00499267 DODGY=0 

Iterating for precision

For large images, a high precision may be needed. The script whatScalePrec.bat iterates until the precision is achieved. It takes the same parameters as whatScale.bat, with one extra parameter, the desired precision eg 1.0001. This might be 1 + 1/max(width,height). A small number of steps should generally be chosen, eg 10.

The script whatScalePrec.bat makes no debugging images. If a debug image is desired, do this after whatScalePrec.bat:

set wsDEBUG=1
call %PICTBAT%whatScale ws_src1.png ws_src2.png again . 10

Example use of whatScalePrec.bat:

for /F "usebackq" %%L ^
in (`%IM%identify ^
  -format "PREC=%%[fx:1+1/max(w,h)]" ws_src1.png`) ^
do set %%L

call %PICTBAT%whatScalePrec ws_src1.png ws_src2.png . . 10 %PREC%
if ERRORLEVEL 1 exit /B 1

echo PREC=%PREC%  SCALE=%wspSCALE% FACT=%wspFACT% DODGY=%wspDODGY% 
PREC=1.00333  SCALE=1.20073049 FACT=1.0028164 DODGY=0 

Acknowledgements

This page was inspired by Grayscale Template-Matching Invariant to Rotation, Scale, Translation, Brightness and Contrast (pdf), by Hae Yong Kim and Sidnei Alves de Araújo.

See also:

Alternative: simple trial and error

Some difficult images (eg from a microscope) have most of the image out of focus. For these, a brute force trial-and-error method may be better. This is implemented in whatScaleT.bat (with a "T").

call %PICTBAT%whatScaleT ws_src1.png ws_src2.png

echo wstSCALE=%wstSCALE% wstCOMP=%wstCOMP% 
wstSCALE=1.19998 wstCOMP=0.00448896 

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

whatScale.bat

@rem Given same-size images %1 and %2,
@rem finds scale S in "-distort SRT S,0" for %1 to best match %2, and a score.

@rem Parameters:
@rem   %3 min scale (default 0.5) OR "again" to iterate from previous run.
@rem   %4 max scale (default 1.5)
@rem   %5 number of scale steps (default 100)
@rem
@rem Also uses:
@rem   wsDO_SCORE_SUB  if ==0, wsSCORE_SUB will not be found.
@rem   wsMETRIC        default RMSE
@rem   wsDEBUG         if 1, creates images for debugging
@rem
@rem Returns:
@rem   wsDODGY     0 if no problem
@rem   wsSCALE     the found scale factor
@rem   wsFACT      error margin, multiple of wsSCALE
@rem   wsSCORE     (0.0 to 1.0, more or less).
@rem   wsSCORE_SUB (0.0 to 1.0, more or less).
@rem
@rem Revised:
@rem   18-August-2016 Tidied up slightly.


@if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal

@call echoOffSave


if "%wsMETRIC%"=="" set wsMETRIC=RMSE

if "%wsDO_SCORE_SUB%"=="" set wsDO_SCORE_SUB=1

set wsMIN_SCALE=%3
if "%wsMIN_SCALE%"=="." set wsMIN_SCALE=
if "%wsMIN_SCALE%"=="" set wsMIN_SCALE=0.5

set wsMAX_SCALE=%4
if "%wsMAX_SCALE%"=="." set wsMAX_SCALE=
if "%wsMAX_SCALE%"=="" set wsMAX_SCALE=1.5

set wsnSTEPS=%5
if "%wsnSTEPS%"=="" set wsnSTEPS=100

if /I "%wsMIN_SCALE%" EQU "again" (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 9 ^
    -format "wsMIN_SCALE=%%[fx:%wsSCALE%/(%wsFACT%*%wsFACT%)]\nwsMAX_SCALE=%%[fx:%wsSCALE%*(%wsFACT%*%wsFACT%)]" ^
    xc:`) do set %%L
)

if "%wsMIN_SCALE%"=="" exit /B 1

set TMPEXT=.miff

call %PICTBAT%setInOut %1 ws
set IN_A=%INFILE%
set TEMP_A_BASE=%TEMP%\%~n1_ws
set TEMP_A=%TEMP%\%~n1_ws_%wsMIN_SCALE%_%wsMAX_SCALE%_%wsnSTEPS%%TMPEXT%

set IN_A_TMP=%TEMP%\%~n1_ws_inA%TMPEXT%

call %PICTBAT%setInOut %2 ws
set IN_B=%INFILE%
set TEMP_B=%TEMP%\%~n2_ws%TMPEXT%
if %IN_B%==%IN_A% set TEMP_B=%TEMP%\%~n2_B_ws%TMPEXT%

set DEBUG_FILE=ws_%~n1_%~n2_dbg%EXT%

echo IN_A=%IN_A% IN_B=%IN_B%

%IM%convert %IN_A% %IN_A_TMP%

for /F "usebackq" %%L ^
in (`%IM%identify -format "WW1=%%w\nHH1=%%h" %IN_A_TMP%`) ^
do set %%L

if "%WW1%"=="" exit /B 1

for /F "usebackq" %%L ^
in (`%IM%identify ^
    -precision 9 ^
    -format "FACT=%%[fx:pow(%wsMAX_SCALE%/%wsMIN_SCALE%,1/%wsnSTEPS%)]" ^
    xc:`) ^
do set %%L

for /F "usebackq" %%L ^
in (`%IM%identify ^
    -precision 9 ^
    -format "FINISHED=%%[fx:abs(%FACT%-1)<0.0000001]" ^
    xc:`) ^
do set %%L

if "%FINISHED%"=="1" (
  set SCALE=%wsMIN_SCALE%

  for /F "usebackq" %%L ^
in (`%IM%identify ^
    -precision 9 ^
    -format "SCALE=%%[fx:sqrt(%wsMIN_SCALE%*%wsMAX_SCALE%)]" ^
    xc:`) ^
do set %%L

  set DODGY=0
  goto end
)

if exist %TEMP_A% goto skipTempA

set SCALE=%wsMIN_SCALE%
set NAMES_A=
for /L %%i in (1,1,%wsnSTEPS%) do (
  @rem Maybe we should crop all scales so we never have virtual pixels.

  %IM%convert ^
  %IN_A_TMP% ^
  -distort SRT !SCALE!,0 ^
  -gravity Center ^
  -virtual-pixel Mirror ^
  -define distort:viewport=%WW1%x%HH1% ^
  ^( -clone 0 -scale "x1^!" ^
     -define distort:viewport=%WW1%x1 -distort SRT 1,0 +repage ^) ^
  ^( -clone 0 -scale "1x^!" ^
     -define distort:viewport=1x%HH1% -distort SRT 1,0 +repage ^
     -rotate 90 +repage ^) ^
  ^( -clone 0 -crop %WW1%x1+0+0 +repage ^) ^
  ^( -clone 0 -crop 1x%HH1%+0+0 +repage -rotate 90 +repage ^) ^
  -delete 0 ^
  +append ^
  %TEMP_A_BASE%_%%i%TMPEXT%

  set NAMES_A=!NAMES_A! %TEMP_A_BASE%_%%i%TMPEXT%

  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 19 -format "SCALE=%%[fx:!SCALE!*%FACT%]" ^
    xc:`) do set %%L
)

rem echo NAMES_A=%NAMES_A%

%IM%convert %NAMES_A% -append %TEMP_A%

:skipTempA

rem %IM%identify %TEMP_A%


if not exist %TEMP_B% %IM%convert ^
  %IN_B% ^
  -gravity Center ^
  -virtual-pixel Mirror ^
  ^( -clone 0 -scale "x1^!" ^) ^
  ^( -clone 0 -scale "1x^!" -rotate 90 +repage ^) ^
  ^( -clone 0 -crop %WW1%x1+0+0 +repage ^) ^
  ^( -clone 0 -crop 1x%HH1%+0+0 +repage -rotate 90 +repage ^) ^
  -delete 0 ^
  +append ^
  %TEMP_B%

rem %IM%identify %TEMP_B%


for /F "usebackq tokens=1-4 delims=()@, " %%R ^
in (`%IM%compare ^
    %TEMP_A% ^
    %TEMP_B% ^
    -similarity-threshold 0 -dissimilarity-threshold 1 -subimage-search ^
    -metric %wsMETRIC% ^
    NULL: 2^>^&1`) ^
do (
  @set COMP_INT=%%R
  @set COMP_FLT=%%S
  @set COMP_XW=%%T
  @set COMP_YW=%%U
)

echo COMP_FLT=%COMP_FLT% COMP_XW=%COMP_XW% COMP_YW=%COMP_YW%

if "%COMP_FLT%" GTR "9" exit /B 1

set DODGY=0
if %COMP_YW% EQU 0 set DODGY=1
if %COMP_YW% GEQ %wsnSTEPS% set DODGY=1

rem What is the magnification here?
set SCALE=%wsMIN_SCALE%
for /L %%i in (1,1,%COMP_YW%) do (
  for /F "usebackq" %%L in (`%IM%identify ^
    -precision 9 -format "SCALE=%%[fx:!SCALE!*%FACT%]" ^
    xc:`) do set %%L
)

rem echo SCALE=%SCALE%

rem Cleanup: remove most temporary files.
for /L %%i in (1,1,%wsnSTEPS%) do (
  @del %TEMP_A_BASE%_%%i%TMPEXT% 2>nul
)


:end

if %wsDO_SCORE_SUB%==1 (
  rem Test result.

  for /F "usebackq" %%L in (`%IM%identify ^
    -format "cropX=%%[fx:int(min(%WW1%,%WW1%*%SCALE%))]\ncropY=%%[fx:int(min(%HH1%,%HH1%*%SCALE%))]" ^
    xc:`) do set %%L

  set ScoreSub=

  for /F "usebackq" %%L in (`%IM%convert ^
    %IN_A_TMP% ^
    -distort SRT "%SCALE%,0" ^
    %IN_B% ^
    -gravity Center ^
    -crop !cropX!x!cropY!+0+0 +repage ^
    -metric %wsMETRIC% -format "ScoreSub=%%[distortion]" -compare ^
    info:`) do set %%L

  if "!ScoreSub!"=="" set DODGY=1
)

if "%wsDEBUG%"=="1" (

  for /F "usebackq" %%L in (`%IM%identify ^
    -format "cropX=%%[fx:int(min(%WW1%,%WW1%*%SCALE%))]\ncropY=%%[fx:int(min(%HH1%,%HH1%*%SCALE%))]" ^
    xc:`) do set %%L

  %IM%convert ^
  %IN_A_TMP% ^
  -virtual-pixel None ^
  ^( %IN_B% ^
    ^( +clone -alpha Transparent ^
       -shave 1x1 ^
       -bordercolor None ^
       -mattecolor #0f0 -frame 1x1 ^
       -channel A -evaluate Multiply 0.75 ^
    ^) ^
    -composite ^
  ^) ^
  ^( -clone -1 ^
     -gravity Center ^
     -crop !cropX!x!cropY!+0+0 ^
     -alpha Transparent ^
     -shave 1x1 ^
     -bordercolor None ^
     -mattecolor #ff0 -frame 1x1 ^
     -channel A -evaluate Multiply 0.75 ^
  ^) ^
  ^( -clone 0 -alpha Transparent ^
     -shave 1x1 ^
     -bordercolor None ^
     -mattecolor #f00 -frame 1x1 ^
     -channel A -evaluate Multiply 0.75 ^
  ^) ^
  -layers merge ^
  +repage ^
  %DEBUG_FILE%

  if ERRORLEVEL 1 exit /B 1
)


call echoRestore

endlocal & set wsSCALE=%SCALE%& set wsFACT=%FACT%& set wsSCORE=%COMP_FLT%& set wsSCORE_SUB=%ScoreSub%& set wsDODGY=%DODGY%

whatScalePrec.bat

@rem Iterates whatScale.bat until required precision.
@rem
@rem Given same-size images %1 and %2,
@rem finds scale S in "-distort SRT S,0" for %1 to best match %2, and a score.

@rem Parameters:
@rem   %3 min scale (default 0.5)
@rem   %4 max scale (default 1.5)
@rem   %5 number of scale steps (default 100)
@rem   %6 iterates until wsFACT <= %6, eg 1.0001

@if "%6"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal

@call echoOffSave


call %PICTBAT%whatScale %1 %2 %3 %4 %5
if not %wsDODGY%==0 (
  set wspDODGY=1
  exit /B 1
)

set wsDO_SCORE_SUB=0
set wsDEBUG=


:loop

set FINISHED=
for /F "usebackq" %%L ^
in (`%IM%identify -format "FINISHED=%%[fx:%wsFACT%<=%6?1:0]" xc:`) ^
do set %%L

if not %FINISHED%==1 (
  call %PICTBAT%whatScale %1 %2 again . %5
  echo wsSCALE=!wsSCALE!
  if not !wsDODGY!==0 (
    set wspDODGY=1
    exit /B 1
  )

  goto loop
)

call echoRestore

endlocal & set wspSCALE=%wsSCALE%& set wspFACT=%wsFACT%& set wspSCORE=%wsSCORE%& set wspDODGY=%wsDODGY%

whatScaleT.bat

@rem Given same-size images %1 and %2,
@rem finds scale S in "-distort SRT S,0" for %1 to best match %2, and a score.
@rem
@rem Parameters:
@rem   %3 min scale (default 0.5)
@rem   %4 max scale (default 1.5)

@rem Unlike whatScale.bat,
@rem this works by brute force trial-and-error of the entire images.
@rem So this may be more suitable when not much of either image is in focus.


@if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal

@call echoOffSave


if "%wstMETRIC%"=="" set wstMETRIC=RMSE

set wstMIN_SCALE=%3
if "%wstMIN_SCALE%"=="." set wstMIN_SCALE=
if "%wstMIN_SCALE%"=="" set wstMIN_SCALE=0.5

set wstMAX_SCALE=%4
if "%wstMAX_SCALE%"=="." set wstMAX_SCALE=
if "%wstMAX_SCALE%"=="" set wstMAX_SCALE=1.5

if "%wstMIN_SCALE%"=="" exit /B 1

set PRECISION=%wstPRECISION%
if "%PRECISION%"=="" set PRECISION=-precision 6


set TMPEXT=.miff
set TMPDIR=%TEMP%

call %PICTBAT%setInOut %1 wst
set IN_A=%INFILE%
set IN_A_TMP=%TMPDIR%\%~n1_wst_inA%TMPEXT%

call %PICTBAT%setInOut %2 wst
set IN_B=%INFILE%
set IN_B_TMP=%TMPDIR%\%~n2_wst_inB%TMPEXT%

set DEBUG_FILE=wst_%~n1_%~n2_dbg%EXT%

if "%~x1"=="%TMPEXT%" (
  set IN_A_TMP=%IN_A%
) else (
  %IM%convert %IN_A% %IN_A_TMP%
)

if "%~x2"=="%TMPEXT%" (
  set IN_B_TMP=%IN_B%
) else (
  %IM%convert %IN_B% %IN_B_TMP%
)

for /F "usebackq" %%L ^
in (`%IM%identify -format "WW1=%%w\nHH1=%%h" %IN_A_TMP%`) ^
do set %%L

if "%WW1%"=="" exit /B 1

set SCALE0=%wstMIN_SCALE%
set SCALE3=%wstMAX_SCALE%

set A_SCALE=%TMPDIR%\%~n1_wst_A_S%TMPEXT%
set B_SCALE=%TMPDIR%\%~n2_wst_B_S%TMPEXT%


call :TryScale %SCALE0%
set COMP0=!COMP!

call :TryScale %SCALE3%
set COMP3=!COMP!

set nIter=0
set FINISHED=0


:loop

if %SCALE0%==%SCALE2% set FINISHED=1

for /F "usebackq" %%L ^
in (`%IM%identify %PRECISION% ^
  -format "SCALE1=%%[fx:%SCALE0%*pow(%SCALE3%/%SCALE0%,1/3)]\nSCALE2=%%[fx:%SCALE0%*pow(%SCALE3%/%SCALE0%,2/3)]" ^
  xc:`) ^
do set %%L

if %SCALE0%==%SCALE1% set FINISHED=1
if %SCALE1%==%SCALE2% set FINISHED=1
if %SCALE2%==%SCALE3% set FINISHED=1

call :TryScale %SCALE1%
set COMP1=!COMP!

call :TryScale %SCALE2%
set COMP2=!COMP!

echo Scale: %SCALE0% %SCALE1% %SCALE2% %SCALE3%
echo Comp: %COMP0% %COMP1% %COMP2% %COMP3%

for /F "usebackq" %%L ^
in (`%IM%identify ^
  -format "High0=%%[fx:%COMP0%>%COMP3%?1:0]\nHigh3=%%[fx:%COMP0%<%COMP3%?1:0]" ^
  xc:`) ^
do set %%L

if %High0%==1 (
  set SCALE0=%SCALE1%
  set COMP0=%COMP1%
) else if %High3%==1 (
  set SCALE3=%SCALE2%
  set COMP3=%COMP2%
) else (
  set FINISHED=1
)

set /A nIter+=1

if %FINISHED%==0 goto loop

echo nIter=%nIter%

call echoRestore

endlocal & set wstSCALE=%SCALE1%& set wstCOMP=%COMP1%

exit /B 0


rem -------------------------------------
rem Subroutines

:TryScale
set SC=%1

for /F "usebackq" %%L ^
in (`%IM%identify ^
  -format "Gtr1=%%[fx:%SC%>1?1:0]\nInvSc=%%[fx:1.0/%SC%]" ^
  xc:`) ^
do set %%L

if %Gtr1%==1 (

  %IM%convert ^
    %IN_A_TMP% ^
    -distort SRT %SC%,0 ^
    %A_SCALE%

  for /F "tokens=2 usebackq delims=() " %%L ^
in (`%IM%compare ^
  %A_SCALE% ^
  %IN_B_TMP% ^
  -metric %wstMETRIC% ^
  NULL: 2^>^&1`) ^
do set COMP=%%L

) else (
  %IM%convert ^
    %IN_B_TMP% ^
    -distort SRT %InvSc%,0 ^
    %B_SCALE%

  for /F "tokens=2 usebackq delims=() " %%L ^
in (`%IM%compare ^
  %IN_A_TMP% ^
  %B_SCALE% ^
  -metric %wstMETRIC% ^
  NULL: 2^>^&1`) ^
do set COMP=%%L

)
exit /B 0

All images on this page were created by the commands shown, using:

%IM%identify -version
Version: ImageMagick 6.9.5-3 Q16 x86 2016-07-22 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Visual C++: 180040629
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib cairo flif freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG to JPG.

Source file for this web page is whatscale.h1. To re-create this web page, run "procH1 whatscale".


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.1 20-Jun-2014.

Page created 18-Aug-2016 05:03:41.

Copyright © 2016 Alan Gibson.