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?"
This page was inspired by:
See also:
We crop a photograph and make three versions:
set wsDEBUG=1 %IMG7%magick ^ %PICTLIB%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: |
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 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.
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=0.998978955 FACT=1.01104669 SCORE_SUB=0.123611 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=1.01001437 FACT=1.01104669 SCORE_SUB=0.127917 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=1.0153545 FACT=1.00043954 SCORE_SUB=0.128556 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=1.01551528 FACT=1.00001758 SCORE_SUB=0.128579 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,
%IMG7%magick ^ %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 |
|
The second image, scaled vertically so we can see it: %IMG7%magick ^ %TEMP%\ws_src2_ws.miff ^ -scale "x50^!" ^ ws_comp2.png |
|
The third image, scaled vertically so we can see it: %IMG7%magick ^ %TEMP%\ws_src3_ws.miff ^ -scale "x50^!" ^ ws_comp3.png |
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:
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.0144746 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.00522089 DODGY=0
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 (`%IMG7%magick 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.0029379 FACT=1.00281641 DODGY=0
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.013761561910179 wstCOMP=0.121781
This method assumes there is no substantial rotation.
Another alternative is to unroll an image ("distort DePolar") scale horizontally to a single column, and rotate that by -90° to get a single row. The pixels in that row then represent the mean colours at different radii from the centre, invariant to rotation. (This is the "Cifi, circular sampling filter" in the Hae Yong Kim paper.)
That's all we do for one image. For the other image, we first resize at various scales, then make a single row for each, then append those vertically. The result represents the image at multiple scales, invariant to rotation. (A quicker method to make this result is to resize the image once, at the maximum scale, and make the single row. Then we resize that row for all the other scales.)
call %PICTBAT%avgConcRings ^ toes.png ws_crings.png |
Now search for the single row that represents one image in the taller image that represents the other image. The y-offset gives us the scale, invariant to rotation. (With a suitable low-level comparison such as my rmsealpha.inc, it can also be invariant to brightness and contrast.)
This method can be developed to find the locations and scales of a subimage in a large image, invariant to rotations. Each candidate location in the large image is cropped, unrolled and scaled, and searched for within the multi-scale of the subimage. With the information loss this inevitably gives false positives, so we then do a second more careful search of only the most promising candidate locations, either by thresholding the scores, or by only searching at locations where the score was a peak.
Calculating the concentric rings is a fairly expensive operation. The method can be first performed on small-scale versions of the images, and the most promising locations searched more carefully.
For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.
@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 %6 CX } Centre for scaling @rem %7 CY } @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. @rem 3-May-2018 Added CX and CY. @rem 10-August-2022 for IM v7. @rem @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @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= if "%wsnSTEPS%"=="" set wsnSTEPS=100 set CX=%6 if "%CX%"=="." set CX= if "%CX%"=="" set CX=0 set CY=%7 if "%CY%"=="." set CY= if "%CY%"=="" set CY=0 echo CX=%CX% CY=%CY% if /I "%wsMIN_SCALE%" EQU "again" ( for /F "usebackq" %%L in (`%IMG7%magick 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 (`%IMG7%magick identify -format "WW1=%%w\nHH1=%%h" %IN_A_TMP%`) ^ do set %%L if "%WW1%"=="" exit /B 1 for /F "usebackq" %%L ^ in (`%IMG7%magick identify ^ -precision 9 ^ -format "FACT=%%[fx:pow(%wsMAX_SCALE%/%wsMIN_SCALE%,1/%wsnSTEPS%)]" ^ xc:`) ^ do set %%L for /F "usebackq" %%L ^ in (`%IMG7%magick 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 (`%IMG7%magick ^ -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. %IMG7%magick ^ %IN_A_TMP% ^ -distort SRT %CX%,%CY%,!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 +repage ^ %TEMP_A_BASE%_%%i%TMPEXT% set NAMES_A=!NAMES_A! %TEMP_A_BASE%_%%i%TMPEXT% for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 19 -format "SCALE=%%[fx:!SCALE!*%FACT%]" ^ xc:`) do set %%L ) rem echo NAMES_A=%NAMES_A% %IM%convert %NAMES_A% -append +repage %TEMP_A% :skipTempA rem %IM%identify %TEMP_A% if not exist %TEMP_B% %IMG7%magick 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 +repage ^ %TEMP_B% rem %IMG7%magick identify %TEMP_B% for /F "usebackq tokens=1-4 delims=()@, " %%R ^ in (`%IMG7%magick 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 (`%IMG7%magick 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 (`%IMG7%magick 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 (`%IMG7%magick ^ %IN_A_TMP% ^ -distort SRT "%CX%,%CY%,%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 (`%IMG7%magick identify ^ -format "cropX=%%[fx:int(min(%WW1%,%WW1%*%SCALE%))]\ncropY=%%[fx:int(min(%HH1%,%HH1%*%SCALE%))]" ^ xc:`) do set %%L %IMG7%magick ^ %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 ^ ^) ^ -compose Over -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%
@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 @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 @rem @rem Updated: @rem 10-August-2022 for IM v7. @rem @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 (`%IMG7%magick 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%
@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 %5 CX } Centre for scaling @rem %6 CY } @rem @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. @rem @rem Updated: @rem 10-August-2022 for IM v7. @rem @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @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 CX=%5 if "%CX%"=="." set CX= if "%CX%"=="" set CX=0 set CY=%6 if "%CY%"=="." set CY= if "%CY%"=="" set CY=0 echo CX=%CX% CY=%CY% 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% echo IN_A=%IN_A% IN_B=%IN_B% if "%~x1"=="%TMPEXT%" ( set IN_A_TMP=%IN_A% ) else ( %IMG7%magick %IN_A% %IN_A_TMP% ) if "%~x2"=="%TMPEXT%" ( set IN_B_TMP=%IN_B% ) else ( %IMG7%magick %IN_B% %IN_B_TMP% ) for /F "usebackq" %%L ^ in (`%IMG7%magick identify ^ -precision 16 ^ -format "WW1=%%w\nHH1=%%h\nInvCX=%%[fx:-(%CX%)]\nInvCY=%%[fx:-(%CY%)]" ^ %IN_A_TMP%`) ^ do set %%L if "%WW1%"=="" exit /B 1 echo InvCX=%InvCX% InvCY=%InvCY% set SCALE0=%wstMIN_SCALE% set SCALE1=0 set SCALE2=0 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 (`%IMG7%magick identify %PRECISION% ^ -precision 16 ^ -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 (`%IMG7%magick 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 (`%IMG7%magick identify ^ -precision 16 ^ -format "Gtr1=%%[fx:%SC%>1?1:0]\nInvSc=%%[fx:1.0/%SC%]" ^ xc:`) ^ do set %%L if %Gtr1%==1 ( %IMG7%magick ^ %IN_A_TMP% ^ -distort SRT %CX%,%CY%,%SC%,0 ^ %A_SCALE% for /F "tokens=2 usebackq delims=() " %%L ^ in (`%IMG7%magick compare ^ %A_SCALE% ^ %IN_B_TMP% ^ -metric %wstMETRIC% ^ NULL: 2^>^&1`) ^ do set COMP=%%L ) else ( %IMG7%magick ^ %IN_B_TMP% ^ -distort SRT %InvCX%,%InvCY%,%InvSc%,0 ^ %B_SCALE% for /F "tokens=2 usebackq delims=() " %%L ^ in (`%IMG7%magick 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:
%IMG7%magick identify -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709 https://imagemagick.org Copyright: (C) 1999 ImageMagick Studio LLC License: https://imagemagick.org/script/license.php Features: Cipher DPC HDRI OpenCL 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 (193231332)
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 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 10-Aug-2022 23:02:32.
Copyright © 2022 Alan Gibson.