snibgo's ImageMagick pages

Searching an image

Searching for the location of one image inside another is very easy. Doing it quickly is harder.

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

Simple search

Here is an easy search. We create a large image and a small image, then search for the best position of the small image within the large one.

Large image:

%IMG7%magick ^
  -size 400x300 xc: ^
  -sparse-color barycentric "0,0 #88f 399,0 #44f 0,299 #2f2 399,299 #484" ^
  si_large.png
si_large.png

Small image:

%IMG7%magick ^
  -size 50x50 xc:#0aa ^
  -sparse-color barycentric "0,0 #0af 49,0 #28f 0,49 #2f2 49,49 #484" ^
  si_sub.png
si_sub.png
%IMG7%magick compare ^
  si_large.png si_sub.png ^
  -metric RMSE ^
  -subimage-search ^
  NULL: 

cmd /c exit /B 0
10728.2 (0.163701) @ 135,144

IM has placed the small image against every possible position within the large image. At each position, it compares the small image with the same area of the large image, using the RMSE metric. It keeps track of the best score. It returns the best score, both as an integer between zero and quantum, and as a floating point from 0.0 to 1.0. It also returns the coordinates of the position of this best score.

Aside: Subimage-search for metric NCC doesn't seem to work:

rem %IMG7%magick compare ^
rem   si_large.png si_sub.png ^
rem   -metric NCC ^
rem   -subimage-search ^
rem   NULL: 

cmd /c exit /B 0

We can get these four values into environment variables, so we can paste the sub-image over the large image at the found position.

for /F "usebackq tokens=1-4 delims=()@, " %%A in (`%IMG7%magick compare ^
  si_large.png si_sub.png ^
  -metric RMSE ^
  -subimage-search ^
  NULL: 2^>^&1`) ^
do (
  set SI_COMP_INT=%%A
  set SI_COMP_FLT=%%B
  set SI_COMP_X=%%C
  set SI_COMP_Y=%%D
)

%IMG7%magick ^
  si_large.png ^
  si_sub.png ^
  -geometry +%SI_COMP_X%+%SI_COMP_Y% ^
  -composite ^
  si_comp.png
si_comp.png

Large images

As mentioned above, IM compares the small image with part of the large image, for every possible position. There are (W-w+1)*(H-h+1) possible positions, where WxH are the dimensions of the large image and wxh are the dimensions of the sub image.

At each position, it does w*h pixel-by-pixel comparisons.

So the total number of pixel-by-pixel comparisons is (W-w+1)*(H-h+1)*w*h.

If both images were twice as wide and twice as high, the number of comparisons would increase by a factor of approximately 24=16. In general the time taken is proportional to linear_dimension4. This is bad news for large images such as digital photographs.

A solution is to reduce the size of both images equally. If each image is halved, the time is reduced to about 1/16th, which is a big improvement. The reduction could be anything we want, giving massive performance increases, but there are two pitfalls:

  1. The result will be less precise. A greater reduction in size results in a greater loss of precision. The cure is to perform a second search of the sub image within a crop of the large image. The size of the crop will be the size of the sub image, plus a margin that reflects the loss of precision.
  2. There is a chance that the best match at a small size doesn't reflect the best match at the full size. After extensive use with real photographs, I have never seen this problem. I have seen it with other types of images. When this problem occurs, a less aggressive reduction can solve it, using siDIV_DIM. For an example, see What rotation? False results.

After many experiments with photographs and video frames, I have concluded that reducing both images such that the minimum dimension is between 10 and 20 pixels works well. However, if the minumum dimension is already between 10 and 19 pixels, we can halve the dimensions.

The script srchImg.bat does two or more searches. The first resizes the images before searching; the last uses the results of the previous to make a crop that will be searched. Any intermediary searches are on a resized crop. When used with set siDEBUG=1, we also get debugging text and an image.

set siDEBUG=1
call %PICTBAT%srchImg si_large.png si_sub.png 
F:\pictures\srchImg: MinDim=50 Offset=(0,0)
:ResizeSrch: 20 5
:ResizeSrch: Creating TMPSRC_RES [C:\Users\Alan\AppData\Local\Temp\siSrc_si_large_20.miff]
:ResizeSrch: 10701.9 0.1633 27 29
:ResizeSrch:   COMP_XW,YW = 135,145 IsDissim=0
:CropResizeSrch: 135,145 10 50 2
:CropResizeSrch: 10725.5 0.163661 6 5
:CropResizeSrch:   COMP_XW,YW = 137,145   IsDissim=0
:CropSrch: 137,145 2
:CropSrch: 10728.2 0.163701 0 1
:CropSrch:   COMP_XW,YW = 135,144   IsDissim=0
echo siCOMP_XW=%siCOMP_XW%  siCOMP_YW=%siCOMP_YW%  siCOMP_FLT=%siCOMP_FLT%  siCOMP_CROP=%siCOMP_CROP% 
siCOMP_XW=135  siCOMP_YW=144  siCOMP_FLT=0.163701  siCOMP_CROP=50x50+135+144 
si_large_si_dbg.png

When the sub-image is small, less than 10 pixels on the shortest dimension, the script doesn't save any time. The greatest savings occur when the sub-image is only slightly smaller than the large image. Sadly, I usually want to search for small sub-images. For real photographs, a sub-image size of 100x100 generally works well, but bigger is faster. Approximates timings for large image 4000x3000, with given sizes of sub-image:

The value returned in siCOMP_FLT is the number in parentheses from IM's compare. Zero is an exact match.

Dissmilarity threshold

The script will use a setting for -dissimilarity-threshold of siDISSIM_THR. By default, this is 1.0.

Any setting of siDISSIM_THR between 0 and 1 will stop the script early if any of the searches have a worse score. This can increase performance when we are looking for exact matches rather than more generally for the best match.

Beware of setting siDISSIM_THR too low. Even if the final search would yield a perfect score of zero, and previous search might not.

The returned variable siIS_DISSIM will be 0 if a match was found within the limit, and 1 if it wasn't.

Real photographs

I took two hand-held photographs with a GoPro camera, pointing the camera in roughly the same direction for both. They are both 4000x3000 pixels. Here is the first, resized for the web, and a crop from the second.

The large image (shown resized for the web):

set WEB_SIZE=-resize 500x500

set SRC=%PICTLIB%20140430\GOPR0166.JPG
set SI_SRC=si_src.jpg
if not exist %SI_SRC% copy %SRC% %SI_SRC%

%IMG7%magick ^
  %SI_SRC% ^
  %WEB_SIZE% ^
  si_photo_sm.jpg
si_photo_sm.jpg

Subimage, taken from the second photo:

%IMG7%magick ^
  %PICTLIB%20140430\GOPR0167.JPG ^
  -crop 200x200+2481+2493 +repage ^
  si_photo_sub.png
si_photo_sub.png

We search for the sub-image, marking the location with a red square:

set siDEBUG=1
set siDEBUG_STROKE=-fill None -stroke #f00 -strokewidth 10
call StopWatch
call %PICTBAT%srchImg %SI_SRC% si_photo_sub.png
call StopWatch 
set siDEBUG=
set siDEBUG_STROKE=
0 00:00:19
echo siCOMP_XW=%siCOMP_XW%  siCOMP_YW=%siCOMP_YW% ^
 siCOMP_FLT=%siCOMP_FLT%  siCOMP_CROP=%siCOMP_CROP% 
siCOMP_XW=2407  siCOMP_YW=2377  siCOMP_FLT=0.121981  siCOMP_CROP=200x200+2407+2377 
%IMG7%magick ^
  si_src_si_dbg.tiff ^
  %WEB_SIZE% ^
  si_src_si_dbg_sm.jpg
si_src_si_dbg_sm.jpg

Crop out what has been found, just to see what it looks like.

%IMG7%magick ^
  %SI_SRC% ^
  -crop %siCOMP_CROP% ^
  si_fnd_crp.png
si_fnd_crp.pngjpg

The difference with the sub-image:

%IMG7%magick ^
  si_photo_sub.png ^
  si_fnd_crp.png ^
  -compose Difference -composite ^
  -auto-level ^
  si_fnd_diff.png
si_fnd_diff.pngjpg

For comparison, here is the same search as a simple IM command:

call StopWatch

%IMG7%magick compare ^
  %SI_SRC% si_photo_sub.png ^
  -metric RMSE ^
  -subimage-search ^
  NULL: 

call StopWatch 
7249.67 (0.110623) @ 1431,1046
0 03:42:53

This takes massively longer: hours instead of seconds. It has found a different solution, numerically slightly better than the script's solution. (The RMSE difference from the sub-image si_photo_sub.png is slightly lower.)

Crop the result found by the simple command, just to see what it looks like.

for /F "usebackq tokens=3,4 delims=()@, " %%X in (si_srch3.lis) do (
  set FND_X=%%X
  set FND_Y=%%Y
)

%IMG7%magick ^
  %SI_SRC% ^
  -crop 200x200+%FND_X%+%FND_Y% +repage ^
  si_fnd_crp2.png
si_fnd_crp2.pngjpg

Although the result from the single command is numerically better, it is clearly wrong. (Previous versions of IM found results that were closer to that of the script.)

Rotations

This script copes with small rotations that are typically found with holding a camera in one's hand, up to around 10°. If the angle is large, eg 45°, it will find false positives. Smaller sub-images are more tolerant of rotations. Searching rotated images are the subject of another page, What rotation?.

Process module

A process module is available for a similar function. See Process modules: multi-scale image search.

Option Description
Short
form
Long form
n noCrop Don't replace input images with crop.
z number sizeDiv number Size divider for multi_scale.
Default: 2.0.
md integer minDim integer Minimum dimension for multi_scale.
Default: 20.
ss integer superSample integer Factor for super-sampling.
Default: 1 (no super-sampling).
string file string Write verbose text to stderr or stdout.
Default: stderr.
v verbose Write some text output to stderr.
version Write version information to stderr.

The script reads and writes image files at each level, which is a large overhead. The process module doesn't read and write so the overhead is far smaller and we adopt a simpler scheme that resizes by 50% at each level. Experimentation suggests that 50% ("sizeDiv 2") is the optimum amount for speed.

The module resizes from each level to the next, so at one level we have a 50% resize of a 50% resize of a 50% resize of the input. It may be more accurate (but slower) to multiply the factors and always resize directly from the input, so we get a 12.5% resize of the input.

call StopWatch

%IM7DEV%magick ^
  %SI_SRC% si_photo_sub.png ^
  -process srchimg ^
  si_pm_out.png >si_pm.lis 2^>^&1

call StopWatch 
0.1219815 @ 2407,2377
0 00:00:10
si_pm_out.pngjpg

Decreasing the minDim parameter will perform a smaller subimage search at the lowest level, which increases performance but also increases the probability of an incorrect result.

call StopWatch

%IM7DEV%magick ^
  %SI_SRC% si_photo_sub.png ^
  -process 'srchimg md 10' ^
  si_pm2_out.png >si_pm2.lis 2^>^&1

call StopWatch 
0.1219815 @ 2407,2377
0 00:00:06
si_pm2_out.pngjpg
call StopWatch

%IM7DEV%magick ^
  %SI_SRC% si_photo_sub.png ^
  -process 'srchimg md 5' ^
  si_pm3_out.png >si_pm3.lis 2^>^&1

call StopWatch 
0.13506816 @ 2476,2615
0 00:00:04
si_pm3_out.pngjpg

The module can super-sample, which gives results precise to sub-pixel. For example, superSample 100 will give a resolution of 0.01 pixels. Internally, this works by resizing the sub-image by that factor, and also a slightly larger crop of the main image by the same factor. So beware of memory requirements when large factors are used with large sub-images.

Super-sampling is useful for long chain-searches, eg tracking movement of features through hundreds of video frames.

Cleanup

We don't need to keep large tiff files, so delete them.

del si_*_*.tiff

Scripts

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

srchImg.bat

rem  Searches image %1 for smaller image %2.
@rem  If dimensions are large, resizes to find approx location,
@rem  and searches again within cropped limits.
@rem  Assumes width and height of %2 is smaller than of %1.
@rem
@rem  Writes results to optional batch file %3. Don't use this; it is for legacy purposes only.
@rem
@rem  Also uses:
@rem    siMETRIC        defaults to RMSE
@rem    siDEBUG         if 1, creates a marked-up copy of image.
@rem    siDEBUG_STROKE  eg "-fill None -stroke #f00 -strokewidth 10" to get thick strokes
@rem    siDELTEMPSRC    if not 0, will remove temporary source (%1) files.
@rem    siDELTEMPSUB    if not 0, will remove temporary subimage (%2) files.
@rem    siDIV_DIM       Divide min dim by this, for purpose of choosing resizes. [1]
@rem    siDISSIM_THR    Dissimilarity threshold. [1]
@rem
@rem  Returns:
@rem    siCOMP_XW, siCOMP_YW coord of top-left of found area
@rem    siCOMP_FLT  RMSE difference beween %2 and found area
@rem    siCOMP_CROP=%subW%x%subH%+%COMP_XW%+%COMP_YW%  crop spec of found area
@rem    siIS_DISSIM 1 if images too dissimilar; otherwise 0

@rem Written: 31 Jan 2014
@rem Revised: 6 May 2014
@rem Revised: 31 May 2014 Don't resize src if already exists.
@rem Revised: 8 August 2016 Tidied, slightly.
@rem Revised: 9 September 2016 Added siDISSIM_THR
@rem Revised: 10-August-2022 for IM v7.
@rem

@rem FIXME: +repage, then add offsets (-format "%X %Y") at end.


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

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 si


set siERROR=0

if "%siDEBUG%"=="1" (
  set DEBUG_OUT=%BASENAME%_si_dbg%EXT%
  if "%siDEBUG_STROKE%"=="" set siDEBUG_STROKE=-fill None -stroke #f00
)

set SRCNAME=%~n1
set SRC=%INFILE%
set SUB=%2
set fBAT=%3
if "%fBAT%"=="" set fBAT=NUL

if "%siMETRIC%"=="" set siMETRIC=RMSE

set TMPEXT=.miff
set TMPDIR=%TEMP%

set SRC_PREF=%TMPDIR%\siSrc_%SRCNAME%
set TMPSRC=%SRC_PREF%%TMPEXT%
set TMPSUB=%TMPDIR%\siSub%TMPEXT%

if not "%siDELTEMPSRC%"=="0" (
  call :delTemp %TMPSRC%
)

if not "%siDELTEMPSUB%"=="0" (
  call :delTemp %TMPSUB%
)

if not "%fBat%"=="NUL" del %fBat% 2>nul

if "%siDIV_DIM%"=="" set siDIV_DIM=1

if "%siDISSIM_THR%"=="" set siDISSIM_THR=1

set subW=
for /F "usebackq" %%L in (`%IMG7%magick ^
  %SUB% ^
  -format "subW=%%w\nsubH=%%h\nMinDim=%%[fx:int((w<h?w:h)/%siDIV_DIM%+0.5)]" ^
  info:`) do set /A %%L

if "%subW%"=="" set siERROR=1

set OFFSET_X=
for /F "usebackq" %%L in (`%IMG7%magick identify ^
  -format "OFFSET_X=%%X\nOFFSET_Y=%%Y" ^
  %SRC%`) do set /A %%L

if "%OFFSET_X%"=="" set siERROR=1

if %siERROR%==1 exit /B 1

echo %0: MinDim=%MinDim% Offset=(%OFFSET_X%,%OFFSET_Y%)

set SIM_DISSIM=-similarity-threshold 0 -dissimilarity-threshold %siDISSIM_THR%
set IsDissim=0

if %MinDim% GEQ 10000 (
  call :ResizeSrch 0.01 1000
  call :CropResizeSrch !COMP_XW! !COMP_YW! 2000 0.2 500
  call :CropResizeSrch !COMP_XW! !COMP_YW! 1000 0.5 200
  call :CropResizeSrch !COMP_XW! !COMP_YW! 400 1 100
  call :CropResizeSrch !COMP_XW! !COMP_YW! 200 2 50
  call :CropResizeSrch !COMP_XW! !COMP_YW! 100 5 20
  call :CropResizeSrch !COMP_XW! !COMP_YW! 40 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 4
) else if %MinDim% GEQ 5000 (
  call :ResizeSrch 0.2 500
  call :CropResizeSrch !COMP_XW! !COMP_YW! 1000 0.5 200
  call :CropResizeSrch !COMP_XW! !COMP_YW! 400 1 100
  call :CropResizeSrch !COMP_XW! !COMP_YW! 200 2 50
  call :CropResizeSrch !COMP_XW! !COMP_YW! 100 5 20
  call :CropResizeSrch !COMP_XW! !COMP_YW! 40 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 4
) else if %MinDim% GEQ 2000 (
  call :ResizeSrch 0.5 200
  call :CropResizeSrch !COMP_XW! !COMP_YW! 400 1 100
  call :CropResizeSrch !COMP_XW! !COMP_YW! 200 2 50
  call :CropResizeSrch !COMP_XW! !COMP_YW! 100 5 20
  call :CropResizeSrch !COMP_XW! !COMP_YW! 40 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 4
) else if %MinDim% GEQ 1000 (
  call :ResizeSrch 1 100
  call :CropResizeSrch !COMP_XW! !COMP_YW! 200 2 50
  call :CropResizeSrch !COMP_XW! !COMP_YW! 100 5 20
  call :CropResizeSrch !COMP_XW! !COMP_YW! 40 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 4
) else if %MinDim% GEQ 500 (
  call :ResizeSrch 2 50
  call :CropResizeSrch !COMP_XW! !COMP_YW! 100 5 20
  call :CropResizeSrch !COMP_XW! !COMP_YW! 40 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 4
) else if %MinDim% GEQ 200 (
  call :ResizeSrch 5 20
  call :CropResizeSrch !COMP_XW! !COMP_YW! 40 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 4
) else if %MinDim% GEQ 100 (
  call :ResizeSrch 10 10
  call :CropResizeSrch !COMP_XW! !COMP_YW! 20 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 2
) else if %MinDim% GEQ 50 (
  call :ResizeSrch 20 5
  call :CropResizeSrch !COMP_XW! !COMP_YW! 10 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 2
) else if %MinDim% GEQ 20 (
  call :ResizeSrch 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 2
) else if %MinDim% GEQ 10 (
  call :ResizeSrch 50 2
  call :CropSrch !COMP_XW! !COMP_YW! 2
) else (
  FOR /F "usebackq tokens=1-4 delims=()@, " %%R ^
IN (`%IMG7%magick compare ^
    %SIM_DISSIM% -subimage-search ^
    -metric %siMETRIC% %SRC% %SUB% NULL: 2^>^&1`) ^
DO (
    if /I %%U GTR A set IsDissim=1
    set COMP_INT=%%R
    set COMP_FLT=%%S
    set COMP_XW=%%T
    set COMP_YW=%%U
  )
)

if %siERROR%==1 (
  echo Error in %0
  exit /B 1
)

rem set /A COMP_XW+=%OFFSET_X%
rem set /A COMP_YW+=%OFFSET_Y%

if "%siDEBUG%"=="1" (
  set /A endX=%COMP_XW%+%subW%-1
  set /A endY=%COMP_YW%+%subH%-1

  rem FIXME: does draw respect offsets? Add +repage to make this irrelevant.

  %IMG7%magick ^
    %SRC% ^
    +repage ^
    %siDEBUG_STROKE% ^
    -draw "rectangle %COMP_XW%,%COMP_YW% !endX!,!endY!" ^
    %DEBUG_OUT%
)

if not "%fBat%"=="NUL" echo set COMP_XW=%COMP_XW%^&set COMP_YW=%COMP_YW%^&set COMP_FLT=%COMP_FLT%^&set COMP_CROP=%subW%x%subH%+%COMP_XW%+%COMP_YW% >%fBat%

for /F "usebackq" %%L in (`%IMG7%magick ^
  %SUB% ^
  -format "centX=%%[fx:int(%COMP_XW%+w/2)]\ncentY=%%[fx:int(%COMP_YW%+h/2)]" ^
  info:`) do set /A %%L

if not "%siDELTEMPSRC%"=="0" (
  call :delTemp %TMPSRC%
)

if not "%siDELTEMPSUB%"=="0" (
  call :delTemp %TMPSUB%
)

if %siERROR%==1 (
  echo Error in %0
  exit /B 1
)

if %IsDissim%==1 (
  set COMP_FLT=1
)

call echoRestore

@endlocal & set siCOMP_XW=%COMP_XW%& set siCOMP_YW=%COMP_YW%& set siCOMP_FLT=%COMP_FLT%& set siIS_DISSIM=%IsDissim%& set siCENT_X=%centX%& set siCENT_Y=%centY%& set siCOMP_CROP=%subW%x%subH%+%COMP_XW%+%COMP_YW%

@exit /B 0



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


:delTemp

if /I "%~x1"==".mpc" del %~dpn1.cache 2>nul
del %1 2>nul

exit /B 0


:ResizeSrch
rem %1 is percentage reduction, eg 50 for 50%. May be <1.
rem %2 is multiplier (=100/%1)

echo %0: %1 %2

rem The convert and compare could be combined into one convert.

set COMP_XW=0
set COMP_YW=0

set TMPSRC_RES=%SRC_PREF%_%1%TMPEXT%

@rem FIXME: +repage, then add offsets (-format "%X %Y") at end.
if not "%siDELTEMPSRC%"=="0" (
  del %TMPSRC_RES% 2>nul
)
if not exist %TMPSRC_RES% (
  echo %0: Creating TMPSRC_RES [%TMPSRC_RES%]
  %IMG7%magick %SRC% +repage -resize %1%% %TMPSRC_RES%
  if ERRORLEVEL 1 set siERROR=1
)

%IMG7%magick %SUB% -resize %1%% %TMPSUB%

if ERRORLEVEL 1 set siERROR=1

set COMP_XW=

FOR /F "tokens=1-4 usebackq delims=()@, " %%R ^
IN (`%IMG7%magick compare ^
    %SIM_DISSIM% -subimage-search ^
    -metric %siMETRIC% %TMPSRC_RES% %TMPSUB% NULL: 2^>^&1`) ^
DO (
    echo %0: %%R %%S %%T %%U
    if /I %%U GTR A set IsDissim=1
    set COMP_INT=%%R
    set COMP_FLT=%%S
    if not "%%T"=="" set /A COMP_XW=%%T*%2
    if not "%%U"=="" set /A COMP_YW=%%U*%2
  )

if "%COMP_XW%"=="" (
  set siERROR=1
  exit /B 1
)

if not "%siDELTEMPSRC%"=="0" (
  del %TMPSRC_RES% 2>nul
)

echo %0:   COMP_XW,YW = %COMP_XW%,%COMP_YW% IsDissim=%IsDissim%

exit /B 0


:CropSrch
rem %1,%2 are coords for top-left of estimated result.
rem %3 is plus or minus for tolerance in both directions.

echo %0: %1,%2 %3

set /A cropL=%1-%3
set /A cropT=%2-%3
if %cropL% LSS 0 set cropL=0
if %cropT% LSS 0 set cropT=0
set /A cropW=%subW%+%3+%3
set /A cropH=%subH%+%3+%3

set COMP_XW=%cropL%
set COMP_YW=%cropT%

if %IsDissim%==1 exit /B 0

%IMG7%magick ^
  %SRC% ^
  +repage ^
  -crop %cropW%x%cropH%+%cropL%+%cropT% ^
  +repage ^
  %TMPSRC%

if ERRORLEVEL 1 (
  set siERROR=1
  exit /B 1
)

set COMP_INT=

for /F "tokens=1-4 usebackq delims=()@, " %%R ^
in (`%IMG7%magick compare ^
    %SIM_DISSIM% -subimage-search ^
    -metric %siMETRIC% %TMPSRC% %SUB% NULL: 2^>^&1`) ^
do (
    echo %0: %%R %%S %%T %%U
    if /I %%U GTR A set IsDissim=1
    set COMP_INT=%%R
    set COMP_FLT=%%S
    if not "%%T"=="" set /A COMP_XW+=%%T
    if not "%%U"=="" set /A COMP_YW+=%%U
)

if "%COMP_INT%"=="" set siERROR=1

echo %0:   COMP_XW,YW = %COMP_XW%,%COMP_YW%   IsDissim=%IsDissim%

exit /B 0


:CropResizeSrch
rem %1,%2 are coords for top-left of estimated result.
rem %3 is plus or minus for tolerance in both directions.
rem %4 is percentage reduction, eg 50 for 50%. May be <1.
rem %5 is multiplier (=100/%4)
rem %1 to %3 are in terms of original full size.

echo %0: %1,%2 %3 %4 %5

set /A cropL=%1-%3
set /A cropT=%2-%3
if %cropL% LSS 0 set cropL=0
if %cropT% LSS 0 set cropT=0
set /A cropW=%subW%+%3+%3
set /A cropH=%subH%+%3+%3

set COMP_XW=%cropL%
set COMP_YW=%cropT%

if %IsDissim%==1 exit /B 0

%IMG7%magick ^
  %SRC% ^
    -crop %cropW%x%cropH%+%cropL%+%cropT% ^
    +repage ^
    -resize %4%% -write %TMPSRC% +delete ^
  %SUB% -resize %4%% %TMPSUB%

if ERRORLEVEL 1 (
  set siERROR=1
  exit /B 1
)

set COMP_INT=

for /F "tokens=1-4 usebackq delims=()@, " %%R ^
in (`%IMG7%magick compare ^
    %SIM_DISSIM% -subimage-search ^
    -metric %siMETRIC% %TMPSRC% %TMPSUB% NULL: 2^>^&1`) ^
do (
    echo %0: %%R %%S %%T %%U
    if /I %%U GTR A set IsDissim=1
    set COMP_INT=%%R
    set COMP_FLT=%%S
    if not "%%T"=="" set /A COMP_XW+=%%T*%5
    if not "%%U"=="" set /A COMP_YW+=%%U*%5
)

if "%COMP_INT%"=="" set siERROR=1

echo %0:   COMP_XW,YW = %COMP_XW%,%COMP_YW%   IsDissim=%IsDissim%

exit /B 0

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

%IMG7%magick -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)

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


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 6-May-2014.

Page created 28-Aug-2022 00:02:15.

Copyright © 2022 Alan Gibson.