snibgo's ImageMagick pages

# Measuring detail

If we are searching for small crops from one image within another image, we want to ensure the crop has detail.

There is no point in searching for a patch of blue in an image of blue sky. The more detail a patch has, the more likely it is to be unique within the other image. (This may not be true for artificial images, but I reckon it's true of ordinary photographs.)

There are two approaches to this problem. One is to rank all of the pixels by some measure, such as the standard deviation of surrounding pixels, and then to find the highest-ranking pixel, the second highest, and so on. The algorithm ensures that chosen pixels are not too close together. That method is explored in Details, details. It is quite slow.

Another approach works in the opposite direction. It starts with a number of regularly-spaces pixels, and calculates are measure for each of these. For those patches with a poor measure (low entropy), we won't bother searching in the other image. This is much faster, as we calculate the measure for a much smaller number of pixels. However, many of the pixels will turn out to be unsuitable. That approach is described in this page.

Set up initial conditions:

```set MD_SRC=\pictures\20140523\AGA_1837_g.tiff

set WEB_SIZE=-resize 500x500```

## A source image

The source photograph for this page has had fairly heavy processing from the raw camera image. This is a challenging image, as there are large areas of no detail (in the sky) and repeated areas of similar detail (the roof tiles, painted brickwork and blinds in the windows).

Put it another way: in this image, the chances of a small crop have high entropy is very low.

On this page, all operations are performed on the full-size image, roughly 7500x5000 pixels. Results are resized for display on the web.

 The source image. ```rem goto skip %IM%convert ^ %MD_SRC% ^ %WEB_SIZE% ^ md_src_sm.jpg```
```for /F "usebackq" %%L in (`%IM%identify -format "WW=%%w\nHH=%%h" %MD_SRC%`) do set %%L
echo %WW% %HH% ```
`7378 4924 `

Generate a list of coordinates.

`call %PICTBAT%nGenCoord %WW% %HH% 6 4 >md_coords.lis`

md_coords.lis contains:

```1054,985
2108,985
3162,985
4216,985
5270,985
6324,985
1054,1970
2108,1970
3162,1970
4216,1970
5270,1970
6324,1970
1054,2954
2108,2954
3162,2954
4216,2954
5270,2954
6324,2954
1054,3939
2108,3939
3162,3939
4216,3939
5270,3939
6324,3939```

Create 24 crops, each 100x100 pixels, centred on these coordinates:

```set ncDEBUG=1
set ncDEBUG_STROKE=-stroke #f00 -fill None -strokewidth 15
set ncCROPDIR=.
set ncEXT=.png
call %PICTBAT%nCrop %MD_SRC% md_coords.lis 100 100

%IM%convert ^
%ncDEBUG_FILE% ^
%WEB_SIZE% ^
mc_crops.jpg```

Here are the 24 crops, shown full size. For convenience, we number these web images.

```for /L %%i in (0,1,23) do (
%IM%convert ^
AGA_1837_g_100_100_crop_%%i.png ^
-stroke None -fill Red -gravity SouthWest -pointsize 20 -annotate 0 "%%i" ^
md_crop_%%i.png
)```

Crops 4, 5, 12, 13 and 20 are featureless, so would have many false matches in another image.

Crops 15, 17 and 22 look useful.

As a better test of which crops are useful, we will search for them within another image that has undergone similar, but not identical, processing.

 Seach for the crops within this image. ```set SRCH_IMG=\pictures\20140523\AGA_1839_g.tiff %IM%convert ^ %SRCH_IMG% ^ %WEB_SIZE% ^ md_srch_sm.jpg```

We search for the crops using the method given in Simple alignment.

```set MATCH_LIS=md_match.lis
del %MATCH_LIS%
set MATCH_LIS2=md_match2.lis

echo CropNum,Score,X,Y >%MATCH_LIS%
set CROP_NUM=0
for /F %%F in (%ncLIST_FILE%) do (
echo %%F

call %PICTBAT%srchImg %SRCH_IMG% %%F
if ERRORLEVEL 1 exit /B 1

echo !CROP_NUM!, !siCOMP_FLT!, !siCENT_X!, !siCENT_Y! >>%MATCH_LIS%

set /A CROP_NUM+=1
)

cSort /i%MATCH_LIS% /o%MATCH_LIS2% /h /kScore```
```CropNum,Score,X,Y
0, 0.0668794, 4419, 2398
1, 0.0127875, 3210, 1926
2, 0.0380188, 4726, 2204
3, 0.0593571, 3105, 420
4, 0.0022269, 6710, 237
5, 0.00497868, 6094, 999
6, 0.0814029, 4376, 2736
7, 0.047739, 2480, 2350
8, 0.11398, 4367, 2374
9, 0.056907, 6039, 4477
10, 0.0517877, 4748, 3212
11, 0.0842783, 6698, 2155
12, 0.0084113, 1187, 4393
13, 0.0217025, 1405, 3110
14, 0.0646012, 4047, 2401
15, 0.0726231, 4599, 3303
16, 0.0772284, 3453, 2313
17, 0.0843147, 4678, 2858
18, 0.0485805, 2517, 4379
19, 0.0422138, 2500, 4571
20, 0.0148356, 3553, 4390
21, 0.040483, 4447, 2597
22, 0.0855242, 5040, 2405
23, 0.0630489, 3449, 2334 ```

These are the matches found, in order of the score, so the closest matches are at the top.

```CropNum,Score,X,Y
4, 0.0022269, 6710, 237
5, 0.00497868, 6094, 999
12, 0.0084113, 1187, 4393
1, 0.0127875, 3210, 1926
20, 0.0148356, 3553, 4390
13, 0.0217025, 1405, 3110
2, 0.0380188, 4726, 2204
21, 0.040483, 4447, 2597
19, 0.0422138, 2500, 4571
7, 0.047739, 2480, 2350
18, 0.0485805, 2517, 4379
10, 0.0517877, 4748, 3212
9, 0.056907, 6039, 4477
3, 0.0593571, 3105, 420
23, 0.0630489, 3449, 2334
14, 0.0646012, 4047, 2401
0, 0.0668794, 4419, 2398
15, 0.0726231, 4599, 3303
16, 0.0772284, 3453, 2313
6, 0.0814029, 4376, 2736
11, 0.0842783, 6698, 2155
17, 0.0843147, 4678, 2858
22, 0.0855242, 5040, 2405
8, 0.11398, 4367, 2374 ```

We can markup a copy of the searched image with the locations found.

 ```:skip set mrCOL_X=3 set mrCOL_Y=4 call %PICTBAT%markRect %SRCH_IMG% md_match.lis 100 100 %IM%convert ^ %mrOUTFILE% ^ %WEB_SIZE% ^ md_srch_marked.jpg```

The closest matches are for crops 4 and 5, but these are at the wrong position in the sky.

Correct matches have been found for only crop numbers 7, 15, and 20. Crop 15 is a correct match but the score is not good because the curtain has moved between photos. Crop 11 is close, but one glass pane too high. 19 is also very close. 20 is also very close, less than 100 pixels out. False matches have been found for rest.

Aside: checking for correct matches isn't possible with these reduced images. I checked the full-size versions by making the two images into layers for Gimp.

`%PICTBAT%toGimp %ncDEBUG_FILE% %mrOUTFILE%`

## The techniques

### Standard deviation

```del md_sd.lis
for /L %%i in (0,1,23) do (
%IM%convert AGA_1837_g_100_100_crop_%%i.png -format "%%i, %%[fx:standard_deviation]\n" info: >>md_sd.lis
)
cSort /imd_sd.lis /omd_sd.lis /k1 /r```
```15, 0.217446
22, 0.166763
11, 0.123797
17, 0.100795
7, 0.092101
16, 0.068679
14, 0.0641415
19, 0.0611273
18, 0.0604791
10, 0.0585896
9, 0.0583192
3, 0.0540542
20, 0.0520365
23, 0.0512842
6, 0.0495721
8, 0.047464
0, 0.0416223
2, 0.0368887
13, 0.036255
21, 0.0320853
1, 0.00956863
12, 0.00800066
5, 0.0070369
4, 0.00379715```

The threshold could be somewhere between 0.06 and 0.10.

### Difference from blur

```del md_lbd.lis
for /L %%i in (0,1,23) do (
%IM%convert ^
AGA_1837_g_100_100_crop_%%i.png ^
^( +clone -blur 0x4 ^) ^
-compose Difference -composite ^
-grayscale RMS ^
-format "%%i, %%[fx:mean]\n" info: >>md_lbd.lis
)
cSort /imd_lbd.lis /omd_lbd.lis /k1 /r```
```11, 0.0402368
18, 0.0341297
22, 0.0284433
17, 0.0270779
3, 0.0249619
14, 0.0242513
23, 0.0241707
0, 0.0232178
15, 0.0221118
8, 0.021639
6, 0.0214891
16, 0.0207127
19, 0.0186017
9, 0.0165609
21, 0.0164521
7, 0.0157946
2, 0.0156873
10, 0.0141526
13, 0.00665879
20, 0.0057895
1, 0.00486209
12, 0.00432354
4, 0.000983201
5, 0.000929366```

The threshold could be somewhere between 0.010 and 0.022.

### Difference between two blurs

```del md_2bd.lis
for /L %%i in (0,1,23) do (
%IM%convert ^
AGA_1837_g_100_100_crop_%%i.png ^
^( -clone 0 -blur 0x4 ^) ^
^( -clone 0 -blur 0x6 ^) ^
-delete 0 ^
-compose Difference -composite ^
-grayscale RMS ^
-format "%%i, %%[fx:mean]\n" info: >>md_2bd.lis
)
cSort /imd_2bd.lis /omd_2bd.lis /k1 /r```
```11, 0.0131496
22, 0.0120719
17, 0.0108971
15, 0.0107203
18, 0.00831235
19, 0.00767631
14, 0.0073792
7, 0.00694394
16, 0.00651588
8, 0.00609133
9, 0.00608128
6, 0.00577632
23, 0.00565061
0, 0.00536901
3, 0.00445679
2, 0.00428925
10, 0.00427402
21, 0.00248127
13, 0.00186595
20, 0.0016006
12, 0.00107566
1, 0.000959411
5, 0.000167381
4, 0.000101817```

The threshold could be somewhere between 0.010 and 0.022.

### Difference of Gaussians

```del md_dog.lis
for /L %%i in (0,1,23) do (
%IM%convert ^
AGA_1837_g_100_100_crop_%%i.png ^
-morphology Convolve DoG:0,4.0,6.0 ^
-grayscale RMS ^
-format "%%i, %%[fx:mean]\n" info: >>md_dog.lis
)
cSort /imd_dog.lis /omd_dog.lis /k1 /r```
```22, 0.0210045
11, 0.019456
17, 0.0178273
15, 0.0174037
18, 0.0153237
14, 0.0133908
19, 0.0129771
7, 0.0124542
16, 0.0116234
9, 0.01044
8, 0.0104363
23, 0.0104016
6, 0.0102716
0, 0.00911032
10, 0.00751994
2, 0.00738392
3, 0.00699886
21, 0.00446465
13, 0.00308597
20, 0.00272584
12, 0.00180523
1, 0.00167776
5, 0.000307883
4, 0.000188003```

The threshold could be somewhere between 0.004 and 0.016.

## Scripts

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

### StopWatch.bat

```@set STOP_WATCH_SUB=
@if not "%STOP_WATCH_TIME%"=="" set STOP_WATCH_SUB=/S "%STOP_WATCH_TIME%"

@cDate %STOP_WATCH_SUB% /f"\q \H:\M:\S"

@for /F "usebackq tokens=*" %%L IN (`cDate /f"\d-\b-\Y \H:\M:\S"`) do @set STOP_WATCH_TIME=%%L
@rem echo %STOP_WATCH_TIME%

@if not "%1"=="" @echo %STOP_WATCH_TIME% %1 %2 %3 %4 %5 %6 %7 %8 %9>>stopwatch.lis```

### nGenCoord.bat

```@rem Given:
@rem   %1 image width
@rem   %2 image height
@rem   %3 number of points horizontally >=1
@rem   %4 number of points vertically >=1
@rem   %5 optional deltaX
@rem   %6 optional deltaY
@rem echoes list of coordinates to stdout.

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

@setlocal enabledelayedexpansion

@call echoOffSave

set deltaX=%5
if "%deltaX%"=="" set deltaX=0

set deltaY=%6
if "%deltaY%"=="" set deltaY=0

for /L %%Y in (1,1,%4) do (
for /L %%X in (1,1,%3) do (

for /F "usebackq" %%L in (`%IM%identify ^
-format "px=%%[fx:int(%%X*%1/(%3+1)+%deltaX%+0.5)]\npy=%%[fx:int(%%Y*%2/(%4+1)+%deltaY%+0.5)]" ^
xc:`) do set %%L

echo !px!,!py!
)
)

@call echoRestore```

### nCrop.bat

```rem From image %1,
rem   list of x,y coordinates in text file %2,
rem   creates crops width %3 height %4 in files *_crop_n.*
rem Also creates text file _crops.lis. Name is returned as ncLIST_FILE.
@rem
@rem Also uses:
@rem   ncDEBUG         if 1, creates a marked-up copy of image.
@rem   ncDEBUG_STROKE  eg to get thick strokes
@rem   ncCROPDIR       directory to place the crops, default %TEMP%
@rem   ncBASE          default name is based on %1, %3 and %4, in directory ncCROPDIR
@rem   ncEXT
@rem
@rem Returns:
@rem   ncLIST_FILE name of created file with list of names of crop files

@rem FIXME: we could also use (optional?) standard deviation of each crop.
@rem Or some other measure, such as difference from a blur.

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

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 nl

if "%ncEXT%"=="" set ncEXT=%EXT%

if "%ncDEBUG%"=="1" set DEBUG_FILE=%BASENAME%_nc_dbg%ncEXT%

if "%ncDEBUG_STROKE%"=="" set ncDEBUG_STROKE=-stroke #f00 -fill None

if "%ncCROPDIR%"=="" set ncCROPDIR=%TEMP%

if "%ncBASE%"=="" set ncBASE=%ncCROPDIR%\%~n1_%3_%4_crop

if "%ncAtBASE%"=="" set ncAtBASE=%~n1_%3_%4_crop

set CROP_FILE=%ncAtBASE%_crops.txt
del %CROP_FILE% 2>nul

set RECT_FILE=%ncBASE%_rects.txt
del %RECT_FILE% 2>nul

set LIST_FILE=%ncBASE%s.lis
del %LIST_FILE% 2>nul

set nCrop=0
rem set sCROP=
set sRECT=

set /A W_2=%3/2
set /A H_2=%4/2

for /F "tokens=1,2 delims=, " %%X in (%2) do (
set /A dx=%%X-%W_2%
set /A dy=%%Y-%H_2%
set IMG_FILE=%ncBASE%_!nCrop!%ncEXT%
rem set sCrop=!sCrop! ^( +clone -crop %3x%4+!dx!+!dy! +repage -write !IMG_FILE! +delete ^)
echo ^( +clone -crop %3x%4+!dx!+!dy! +repage -write !IMG_FILE! +delete ^) >> %CROP_FILE%
echo !IMG_FILE!>>%LIST_FILE%
set /A nCrop+=1

if "%ncDEBUG%"=="1" (
set /A endX=!dx!+%3-1
set /A endY=!dy!+%4-1
set sRECT=!sRECT! rectangle !dx!,!dy!,!endX!,!endY!
echo rectangle !dx!,!dy!,!endX!,!endY! >>%RECT_FILE%
rem FIXME: also annotate the rectangles
)
)

%IM%convert ^
%INFILE% ^
@%CROP_FILE% ^
NULL:
if ERRORLEVEL 1 exit /B 1

if "%ncDEBUG%"=="1" (
%IM%convert ^
%INFILE% ^
%ncDEBUG_STROKE% ^
-draw @%RECT_FILE% ^
%DEBUG_FILE%

if ERRORLEVEL 1 exit /B 1
)

@call echoRestore

@endlocal & set ncLIST_FILE=%LIST_FILE%& set ncDEBUG_FILE=%DEBUG_FILE%```

### markRect.bat

```rem Given image %1, creates marked-up version with numbered rectangles.
rem Takes coordinates of rectangle centres from file %2.
rem %3 width of rectangle, default 1
rem %4 height of rectangle, default 1
@rem
@rem %2 is CSV file with columns X,Y{,N}
@rem If third column is present, uses this for annotation.
@rem Otherwise numbers seqentially.
@rem
@rem Also uses:
@rem   mrSTROKE  eg to get thick strokes
@rem   mrPIX_HT  height of font in pixels. If 0, no numbering.
@rem   mrCOL_X   column number in %2 for x-coordinate, counting from 1
@rem   mrCOL_Y   column number in %2 for y-coordinate, counting from 1

@rem FIXME: Also option for circles? Ellipes?

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

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 mr

if "%mrSTROKE%"=="" set mrSTROKE=-stroke #f00 -fill None

if "%mrPIX_HT%"=="" set mrPIX_HT=20

if "%mrCOL_X%"=="" set mrCOL_X=1

if "%mrCOL_Y%"=="" set mrCOL_Y=2

set RW=%3
if "%RW%"=="" set RW=1

set RH=%4
if "%RW%"=="" set RH=1

set /A W_2=%RW%/2
set /A H_2=%RH%/2

set nCrop=0
set sRECT=
set sNUMB=

call %PICTBAT%getPointSize %INFILE% %H_2%
set mrTEXT=-pointsize %gpPointsize% -fill #f00 -stroke None

for /F "tokens=%mrCOL_X%,%mrCOL_Y% delims=, " %%X in (%2) do (
if not "%%X" GTR "a" (
set /A dx=%%X-%W_2%
set /A dy=%%Y-%H_2%

set /A endX=!dx!+%RW%-1
set /A endY=!dy!+%RH%-1
set sRECT=!sRECT! rectangle !dx!,!dy!,!endX!,!endY!
set ANNOT=%%Z
if "%ANNOT%"=="" set ANNOT=!nCrop!
if not "%mrPIX_HT%"=="0" set sNUMB=!sNUMB! text %%X,%%Y '!ANNOT!'

set /A nCrop+=1
)
)

if "%mrPIX_HT%"=="0" (
set sTEXT=
) else (
set sTEXT=%mrTEXT% -draw "%sNUMB%"
)

%IM%convert ^
%INFILE% ^
%mrSTROKE% ^
-draw "%sRECT%" ^
%sTEXT% ^
%OUTFILE%

@call echoRestore

@endlocal & set mrOUTFILE=%OUTFILE%```

### toGimp.bat

```setlocal

set TEMP_TIFF=%TEMP%\tg.tiff
set TEMP_XCF=%TEMP%\tg.xcf

%IM%convert ^
%* ^
-set label %%f ^
-type TrueColorAlpha ^
-compress zip ^
%TEMP_TIFF%

start %GIMP% %TEMP_XCF%```

### srchImg.bat

```rem  Searches image %1 for image %2.
@rem  Writes results to optional batch file %3. Don't use this; it is for legacy purposes only.
@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  Also uses:
@rem    siMETRIC defaults to RMSE
@rem    siDEBUG if 1, creates a marked-up copy of image.
@rem    siDEBUG_STROKE eg to get thick strokes
@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 Written: 31 Jan 2014
@rem Revised: 6 May 2014
@rem Revised: 31 May 2014 Don't resize src if already exists.

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

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

@setlocal

@call echoOffSave

call %PICTBAT%setInOut %1 si

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 TMPSRC=%TMPDIR%\siSrc%TMPEXT%
set TMPSUB=%TMPDIR%\siSub%TMPEXT%

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

FOR /F "usebackq" %%L ^
IN (`%IM%convert -ping %SUB% -format "subW=%%w\nsubH=%%h\nMinDim=%%[fx:w<h?w:h]" info:`) ^
DO set /A %%L

FOR /F "usebackq" %%L ^
IN (`%IM%identify -format "OFFSET_X=%%X\nOFFSET_Y=%%Y" %SRC%`) ^
DO set /A %%L

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

if %MinDim% GEQ 10000 (
call :ResizeSrch 0.1 1000
call :CropSrch !COMP_XW! !COMP_YW! 2000
) else if %MinDim% GEQ 5000 (
call :ResizeSrch 0.2 500
call :CropSrch !COMP_XW! !COMP_YW! 1000
) else if %MinDim% GEQ 2000 (
call :ResizeSrch 0.5 200
call :CropSrch !COMP_XW! !COMP_YW! 400
) else if %MinDim% GEQ 1000 (
call :ResizeSrch 1 100
call :CropSrch !COMP_XW! !COMP_YW! 200
) 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 :CropSrch !COMP_XW! !COMP_YW! 20
) else if %MinDim% GEQ 50 (
call :ResizeSrch 20 5
call :CropSrch !COMP_XW! !COMP_YW! 10
) 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 (`%IM%compare ^
-similarity-threshold 0 -dissimilarity-threshold 1 -subimage-search ^
-metric %siMETRIC% %SRC% %SUB% NULL: 2^>^&1`) ^
DO (
set COMP_INT=%%R
set COMP_FLT=%%S
set COMP_XW=%%T
set COMP_YW=%%U
)
)

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.

%IM%convert ^
%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 (`%IM%convert -ping %SUB% -format "centX=%%[fx:%COMP_XW%+w/2]\ncentY=%%[fx:%COMP_YW%+h/2]" info:`) ^
DO set /A %%L

call echoRestore

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

exit /B 0

:error
echo Error in %0
exit /B 1

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

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

echo ResizeSrch %1 %2

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

set COMP_XW=0
set COMP_YW=0

set TMPSRC_RES=%TMPDIR%\%SRCNAME%_si_%1%TMPEXT%

@rem FIXME: +repage, then add offsets (-format "%X %Y") at end.
if not exist %TMPSRC_RES% %IM%convert %SRC% +repage -resize %1%% %TMPSRC_RES%

%IM%convert %SUB% -resize %1%% %TMPSUB%

set COMP_XW=

FOR /F "tokens=1-4 usebackq delims=()@, " %%R ^
IN (`%IM%compare ^
-similarity-threshold 0 -dissimilarity-threshold 1 -subimage-search ^
-metric %siMETRIC% %TMPSRC_RES% %TMPSUB% NULL: 2^>^&1`) ^
DO (
rem echo %%R %%S %%T %%U
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%"=="" exit /B 1

echo   COMP_XW, YW = %COMP_XW% %COMP_YW%

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 CropSrch %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%

%IM%convert ^
%SRC% ^
+repage ^
-crop %cropW%x%cropH%+%cropL%+%cropT% ^
+repage ^
%TMPSRC%

FOR /F "tokens=1-4 usebackq delims=()@, " %%R ^
IN (`%IM%compare ^
-similarity-threshold 0 -dissimilarity-threshold 1 -subimage-search ^
-metric %siMETRIC% %TMPSRC% %SUB% NULL: 2^>^&1`) ^
DO (
rem echo %%R %%S %%T %%U
set COMP_INT=%%R
set COMP_FLT=%%S
if not "%%T"=="" set /A COMP_XW+=%%T
if not "%%U"=="" set /A COMP_YW+=%%U
)

echo   COMP_XW, YW = %COMP_XW% %COMP_YW%

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/%1)
rem %1 to %3 are in terms of original full size.

echo CropResizeSrch %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%

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

FOR /F "tokens=1-4 usebackq delims=()@, " %%R ^
IN (`%IM%compare ^
-similarity-threshold 0 -dissimilarity-threshold 1 -subimage-search ^
-metric %siMETRIC% %TMPSRC% %TMPSUB% NULL: 2^>^&1`) ^
DO (
echo %%R %%S %%T %%U
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
)

echo   COMP_XW, YW = %COMP_XW% %COMP_YW%

exit /B 0
```

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

`%IM%identify -version`
```Version: ImageMagick 6.8.9-0 Q16 x64 2014-04-06 http://www.imagemagick.org
Features: DPC OpenMP
Delegates: bzlib cairo freetype jbig jng jp2 jpeg lcms lqr pangocairo png ps rsvg tiff webp xml zlib
```

Source file for this web page is mtokens=1-4 usebackq delims=()@, " %%R ^ IN (`%IM%compare ^ -similarity-threshold 0 -dissimilarity-threshold 1 -subimage-search ^ -metric %siMETRIC% %TMPSRC% %TMPSUB% NULL: 2^>^&1`) ^ DO ( echo %%R %%S %%T %%U 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 ) rem echo COMP_XW, YW = %COMP_XW% %COMP_YW% exit /B 0

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

`%IM%identify -version`
```Version: ImageMagick 6.9.1--6 Q16 x64 2015-06-20 http://www.imagemagick.org
Features: Cipher DPC Modules OpenMP
Delegates (built-in): bzlib cairo freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib
```

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

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.