snibgo's ImageMagick pages

Find four corners

Three simple methods.

Suppose we have a white shape on a black background, and the shape is approximately a quadrangle. (That is, it has four approximately straight lines, and four angles.) We want to find the coordinates of its corners.

Sample inputs

An exact rectangle.

%IM%convert ^
  -size 300x200 xc:Black ^
  -fill White ^
  -draw "polygon 30,40 230,40 230,140 30,140" ^
  f4c_rect.png
f4c_rect.png

A general quadrangle.

%IM%convert ^
  -size 300x200 xc:Black ^
  -fill White ^
  -draw "polygon 50,50 250,60 230,140 60,150" ^
  f4c_quad.png
f4c_quad.png

A more general shape.

is_easy_mainland.png

is_easy_mainland.png

A more distorted quadrangle.

%IM%convert ^
  -size 300x200 xc:Black ^
  -fill White ^
  -draw "polygon 30,30 250,60 220,130 60,150" ^
  f4c_quadf.png
f4c_quadf.png

This is a large image, reduced for the web.

set PHOTO_SRC=pbp_threshpap.tiff

set WEB_SIZE=-resize 600x600

%IM%convert ^
  %PHOTO_SRC% ^
  %WEB_SIZE% ^
  f4c_phsrc_sm.jpg
f4c_phsrc_sm.jpg

Method: sub-image searching

The script find4cornSub.bat does a subimage-search for a small image that represents a corner.

To get a reasonble performance on large images, it shrinks the image to 1/20 of the full size, searches that, and uses the result to search a small crop of the full-size image. If the result is a poor match, it repeats repeats with a less aggressive shrinkage, until the result is good or the shrinkage factor reaches 1.0.

call %PICTBAT%find4cornSub ^
  f4c_rect.png F4C_rect_sub f4c_rect_sub_out.png
if ERRORLEVEL 1 goto :error

set F4C_rect_sub 
F4C_rect_sub.BL.x=30
F4C_rect_sub.BL.y=141
F4C_rect_sub.BR.x=231
F4C_rect_sub.BR.y=141
F4C_rect_sub.TL.x=30
F4C_rect_sub.TL.y=40
F4C_rect_sub.TR.x=231
F4C_rect_sub.TR.y=40
f4c_rect_sub_out.png
call %PICTBAT%find4cornSub ^
  f4c_quad.png F4C_quad_sub f4c_quad_sub_out.png
if ERRORLEVEL 1 goto :error

set F4C_quad_sub 
F4C_quad_sub.BL.BAD=1
F4C_quad_sub.BL.x=60
F4C_quad_sub.BL.y=151
F4C_quad_sub.BR.BAD=1
F4C_quad_sub.BR.x=231
F4C_quad_sub.BR.y=141
F4C_quad_sub.TL.x=50
F4C_quad_sub.TL.y=50
F4C_quad_sub.TR.BAD=1
F4C_quad_sub.TR.x=251
F4C_quad_sub.TR.y=60
f4c_quad_sub_out.png
call %PICTBAT%find4cornSub ^
  is_easy_mainland.png F4C_iem_sub f4c_iem_sub_out.png
if ERRORLEVEL 1 goto :error

set F4C_iem_sub 
F4C_iem_sub.BL.BAD=1
F4C_iem_sub.BL.x=21
F4C_iem_sub.BL.y=174
F4C_iem_sub.BR.BAD=1
F4C_iem_sub.BR.x=291
F4C_iem_sub.BR.y=172
F4C_iem_sub.TL.x=18
F4C_iem_sub.TL.y=25
F4C_iem_sub.TR.x=298
F4C_iem_sub.TR.y=44
f4c_iem_sub_out.png
call %PICTBAT%find4cornSub ^
  f4c_quadf.png F4C_quadf_sub f4c_quadf_sub_out.png
if ERRORLEVEL 1 goto :error

set F4C_quadf_sub 
F4C_quadf_sub.BL.BAD=1
F4C_quadf_sub.BL.x=60
F4C_quadf_sub.BL.y=151
F4C_quadf_sub.BR.BAD=1
F4C_quadf_sub.BR.x=221
F4C_quadf_sub.BR.y=131
F4C_quadf_sub.TL.BAD=1
F4C_quadf_sub.TL.x=30
F4C_quadf_sub.TL.y=30
F4C_quadf_sub.TR.BAD=1
F4C_quadf_sub.TR.x=251
F4C_quadf_sub.TR.y=60
f4c_quadf_sub_out.png
call %PICTBAT%find4cornSub ^
  %PHOTO_SRC% F4C_ph_sub f4c_ph_sub_out.miff ". 200 20"
if ERRORLEVEL 1 goto :error

%IM%convert ^
  f4c_ph_sub_out.miff ^
  %WEB_SIZE% ^
  f4c_ph_sub_out_sm.jpg

set F4C_ph_sub 
F4C_ph_sub.BL.x=401
F4C_ph_sub.BL.y=6832
F4C_ph_sub.BR.x=2570
F4C_ph_sub.BR.y=4433
F4C_ph_sub.TL.x=1991
F4C_ph_sub.TL.y=1208
F4C_ph_sub.TR.x=4532
F4C_ph_sub.TR.y=798

Two calculated corners are bad.

f4c_ph_sub_out_sm.jpg

Method: blurred edges

The script find4cornEdgeBlr.bat finds edges, making them light while other pixels are black. Then it blurs this image so the lighter pixels show where corners occur in the edge; lightness represents the energy of the edge. In each quarter of the image, the lightest pixel is at the corner.

We could use any edge-detector. slopeMag.bat doesn't introduce stair-casing.

The blur needs to be fairly large to capture the corners of is_easy_mainland.png. However, large blurs also calculate the position of the corners to be slightly inside their true positions.

call %PICTBAT%find4cornEdgeBlr ^
  f4c_rect.png F4C_rect_be f4c_rect_be_out.png
if ERRORLEVEL 1 goto :error

set F4C_rect_be 
F4C_rect_be.BL.x=32
F4C_rect_be.BL.y=138
F4C_rect_be.BR.x=228
F4C_rect_be.BR.y=138
F4C_rect_be.TL.x=32
F4C_rect_be.TL.y=42
F4C_rect_be.TR.x=228
F4C_rect_be.TR.y=42
f4c_rect_be_out.png
call %PICTBAT%find4cornEdgeBlr ^
  f4c_quad.png F4C_quad_be f4c_quad_be_out.png
if ERRORLEVEL 1 goto :error

set F4C_quad_be 
F4C_quad_be.BL.x=62
F4C_quad_be.BL.y=148
F4C_quad_be.BR.x=229
F4C_quad_be.BR.y=138
F4C_quad_be.TL.x=53
F4C_quad_be.TL.y=52
F4C_quad_be.TR.x=247
F4C_quad_be.TR.y=62
f4c_quad_be_out.png
call %PICTBAT%find4cornEdgeBlr ^
  is_easy_mainland.png F4C_iem_be f4c_iem_be_out.png
if ERRORLEVEL 1 goto :error

set F4C_iem_be 
F4C_iem_be.BL.x=26
F4C_iem_be.BL.y=174
F4C_iem_be.BR.x=299
F4C_iem_be.BR.y=150
F4C_iem_be.TL.x=23
F4C_iem_be.TL.y=20
F4C_iem_be.TR.x=281
F4C_iem_be.TR.y=31
f4c_iem_be_out.png
call %PICTBAT%find4cornEdgeBlr ^
  f4c_quadf.png F4C_quadf_be f4c_quadf_be_out.png
if ERRORLEVEL 1 goto :error

set F4C_quadf_be 
F4C_quadf_be.BL.x=61
F4C_quadf_be.BL.y=147
F4C_quadf_be.BR.x=220
F4C_quadf_be.BR.y=128
F4C_quadf_be.TL.x=33
F4C_quadf_be.TL.y=33
F4C_quadf_be.TR.x=247
F4C_quadf_be.TR.y=62
f4c_quadf_be_out.png
call %PICTBAT%find4cornEdgeBlr ^
  %PHOTO_SRC% F4C_ph_be f4c_ph_be_out.miff ". 200 20"
if ERRORLEVEL 1 goto :error

%IM%convert ^
  f4c_ph_be_out.miff ^
  %WEB_SIZE% ^
  f4c_ph_be_out_sm.jpg

set F4C_ph_be 
F4C_ph_be.BL.x=381
F4C_ph_be.BL.y=6832
F4C_ph_be.BR.x=3768
F4C_ph_be.BR.y=4621
F4C_ph_be.TL.x=173
F4C_ph_be.TL.y=1481
F4C_ph_be.TR.x=4383
F4C_ph_be.TR.y=809

Three calculated corners are bad.

f4c_ph_be_out_sm.jpg

Method: skeleton junctions

The script find4cornSkelJcn.bat finds slope magnitudes, thins that to a skeleton, and finds junctions.

call %PICTBAT%find4cornSkelJcn ^
  f4c_rect.png F4C_rect_sj f4c_rect_sj_out.png
if ERRORLEVEL 1 goto :error

set F4C_rect_sj 
F4C_rect_sj=dummy
f4c_rect_sj_out.png
call %PICTBAT%find4cornSkelJcn ^
  f4c_quad.png F4C_quad_sj f4c_quad_sj_out.png
if ERRORLEVEL 1 goto :error

set F4C_quad_sj 
F4C_quad_sj=dummy
f4c_quad_sj_out.png
call %PICTBAT%find4cornSkelJcn ^
  is_easy_mainland.png F4C_iem_sj f4c_iem_sj_out.png
if ERRORLEVEL 1 goto :error

set F4C_iem_sj 
F4C_iem_sj=dummy
f4c_iem_sj_out.png
call %PICTBAT%find4cornSkelJcn ^
  f4c_quadf.png F4C_quadf_sj f4c_quadf_sj_out.png
if ERRORLEVEL 1 goto :error

set F4C_quadf_sj 
F4C_quadf_sj=dummy
f4c_quadf_sj_out.png

This method is slow and useless for photos.

goto skipPhSj
call %PICTBAT%find4cornSkelJcn ^
  %PHOTO_SRC% F4C_ph_sj f4c_ph_sj_out.miff ". 200 20"
if ERRORLEVEL 1 goto :error

%IM%convert ^
  f4c_ph_sj_out.miff ^
  %WEB_SIZE% ^
  f4c_ph_sj_out_sm.jpg

set F4C_ph_sj 

:skipPhSj
@f4c_ph_sj.lis

[No image]

Method: polar distance

The script find4cornPolDist.bat trims to the shape, and crops the result into quarters. For each image quarter, it finds the point in the shape that is furthest from the centre.

To do this, it unrolls the trimmed image and crops horizontally into four pieces. In each piece, the x- and y-coordinates of the first white pixel give the polar coordinates (r,θ) of the point on the shape that is furthest from the centre.

From those polar coordinates (r,θ), it calculates the cartesian coordinates (x,y) within the trimmed image. Adding the canvas offsets of the trimmed image gives the cartesian coordinates within the input image.

With no supersampling, the results can be a few pixels out.

set SUPSAMP=300
call %PICTBAT%find4cornPolDist ^
  f4c_rect.png F4C_rect f4c_rect_out.png 1 %SUPSAMP%
if ERRORLEVEL 1 goto :error

set F4C_rect. 
F4C_rect.BL.x=30.103396959450308
F4C_rect.BL.y=140.37642969635249
F4C_rect.BR.x=230.37145605363503
F4C_rect.BR.y=141.41982332121498
F4C_rect.TL.x=30.364611445792733
F4C_rect.TL.y=40.101189493849745
F4C_rect.TR.x=231.15509242241473
F4C_rect.TR.y=41.147304928990437
f4c_rect_out.png
call %PICTBAT%find4cornPolDist ^
  f4c_quad.png F4C_quad f4c_quad_out.png 1 %SUPSAMP%
if ERRORLEVEL 1 goto :error

set F4C_quad. 
F4C_quad.BL.x=60.400531873670303
F4C_quad.BL.y=150.0448281292978
F4C_quad.BR.x=230.28537989977457
F4C_quad.BR.y=140.13689777193582
F4C_quad.TL.x=50.364611445792733
F4C_quad.TL.y=50.101189493849745
F4C_quad.TR.x=249.72864540695906
F4C_quad.TR.y=61.725986117608677
f4c_quad_out.png
call %PICTBAT%find4cornPolDist ^
  is_easy_mainland.png F4C_iem f4c_iem_out.png 1 %SUPSAMP%
if ERRORLEVEL 1 goto :error

set F4C_iem. 
F4C_iem.BL.x=20.491713538790492
F4C_iem.BL.y=170.95343994328152
F4C_iem.BR.x=299.25384575235074
F4C_iem.BR.y=156.48850742726876
F4C_iem.TL.x=18.827024742474464
F4C_iem.TL.y=25.80758398269522
F4C_iem.TR.x=305.90166250501602
F4C_iem.TR.y=72.297807340089747
f4c_iem_out.png

The calculated top-right corner might not be the point that a human would choose.

In the following case, the bottom-right corner of the trimmed image contains the corner but the corner is not the point that is furthest from the centre.

call %PICTBAT%find4cornPolDist ^
  f4c_quadf.png F4C_quadf f4c_quadf_out.png 1 %SUPSAMP%
if ERRORLEVEL 1 goto :error

set F4C_quadf. 
F4C_quadf.BL.x=60.453817680964093
F4C_quadf.BL.y=148.59902449947259
F4C_quadf.BR.x=236.2632823965844
F4C_quadf.BR.y=92.542272592369386
F4C_quadf.TL.x=31.765576507987788
F4C_quadf.TL.y=31.111310624177626
F4C_quadf.TR.x=249.41247818835348
F4C_quadf.TR.y=61.178663202270755
f4c_quadf_out.png

The large photograph doesn't need the precision that supersampling would provide. Anyhow, it would eat all my memory.

set SUPSAMP=
call %PICTBAT%find4cornPolDist ^
  %PHOTO_SRC% F4C_phot f4c_phot_out.miff 1 %SUPSAMP% . ". 200 20"
if ERRORLEVEL 1 goto :error

%IM%convert ^
  f4c_phot_out.miff ^
  %WEB_SIZE% ^
  f4c_phot_out_sm.jpg

set F4C_phot. 
F4C_phot.BL.x=-1.4416038010367629
F4C_phot.BL.y=6998.5572365735807
F4C_phot.BR.x=4697.4625140719709
F4C_phot.BR.y=6806.1117192173169
F4C_phot.TL.x=6.4897686500498821
F4C_phot.TL.y=713.30392076449562
F4C_phot.TR.x=4606.7887503524507
F4C_phot.TR.y=809.03864714996462
f4c_phot_out_sm.jpg

Two calculated corners are good, but two are bad. The script could easily identify one of the corners as bad, but not the other.

Conclusions

For the clean images of quadrangles, the subimage-searching and blurred edges methods (find4cornSub.bat and find4cornEdgeBlr.bat) work well, correctly identifying the corners. These methods also give plausible results for is_easy_mainland that has no "correct" answers.

The polar distance method (find4cornPolDist.bat) misidentifies a corner in f4c_quadf.png, and produces poorer results for is_easy_mainland.

None of the methods give good results for the photo of the book page. That needs a more sophisticated method, such as by finding the page edges and extrapolating the linear regression of those.

Scripts

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

find4cornSub.bat

rem Given %1 is image, whitish quadrangle on blackish background,
rem finds the four corners by subimage search.
rem Writes enviroment variable prefix %2
rem and output image %3.
rem %4 is three (quoted) parameters for drawCircs.bat: colour, radius, strokewidth.

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

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 f4cs


set ENV_PREF=%2
if "%ENV_PREF%"=="." set ENV_PREF=
if "%ENV_PREF%"=="" set ENV_PREF=f4csENV

set OUTFILE=%3
if "%OUTFILE%"=="." set OUTFILE=
if /I "%OUTFILE%"=="NULL:" set OUTFILE=

set dcPARAMS=%~4
if "%dcPARAMS%"=="." set dcPARAMS=
if "%dcPARAMS%"=="" set dcPARAMS=. . .


set CORNER=f4cs_dcCorner.miff

set QUARTERS=f4cs_dcQuarters.miff


set SRCH_FACT=2
set SRCH_FACT=20
set SRCH_FACT=10
set SRCH_FACT=20

%IM%convert ^
  %INFILE% ^
  -crop 2x2@ ^
  %QUARTERS%

:: Top-left
%IM%convert ^
  -size 4x4 xc:Black ^
  -fill White ^
  -draw "rectangle 2,2 3,3" ^
  %CORNER%

set subSemiW=2
set subSemiH=2

call %PICTBAT%subSrchFactRep %QUARTERS%[0] %CORNER% %SRCH_FACT% F4Csub

for /F "usebackq" %%L in (`%IM%identify ^
  -format "%ENV_PREF%.TL.x=%%X+%%[fx:int(%F4Csub.x%+%subSemiW%+0.5)]\n%ENV_PREF%.TL.y=%%Y+%%[fx:int(%F4Csub.y%+%subSemiH%+0.5)]" ^
  %QUARTERS%[0]`) do set /A %%L

set %ENV_PREF%.TL.BAD=%F4Csub.BAD%


:: Top-right
%IM%convert ^
  %CORNER% ^
  -rotate 90 ^
  %CORNER%

call %PICTBAT%subSrchFactRep %QUARTERS%[1] %CORNER% %SRCH_FACT% F4Csub

for /F "usebackq" %%L in (`%IM%identify ^
  -format "%ENV_PREF%.TR.x=%%X+%%[fx:int(%F4Csub.x%+%subSemiW%+0.5)]\n%ENV_PREF%.TR.y=%%Y+%%[fx:int(%F4Csub.y%+%subSemiH%+0.5)]" ^
  %QUARTERS%[1]`) do set /A %%L

set %ENV_PREF%.TR.BAD=%F4Csub.BAD%


:: Bottom-right
%IM%convert ^
  %CORNER% ^
  -rotate 90 ^
  %CORNER%

call %PICTBAT%subSrchFactRep %QUARTERS%[3] %CORNER% %SRCH_FACT% F4Csub

for /F "usebackq" %%L in (`%IM%identify ^
  -format "%ENV_PREF%.BR.x=%%X+%%[fx:int(%F4Csub.x%+%subSemiW%+0.5)]\n%ENV_PREF%.BR.y=%%Y+%%[fx:int(%F4Csub.y%+%subSemiH%+0.5)]" ^
  %QUARTERS%[3]`) do set /A %%L

set %ENV_PREF%.BR.BAD=%F4Csub.BAD%


:: Bottom-left
%IM%convert ^
  %CORNER% ^
  -rotate 90 ^
  %CORNER%

call %PICTBAT%subSrchFactRep %QUARTERS%[2] %CORNER% %SRCH_FACT% F4Csub

for /F "usebackq" %%L in (`%IM%identify ^
  -format "%ENV_PREF%.BL.x=%%X+%%[fx:int(%F4Csub.x%+%subSemiW%+0.5)]\n%ENV_PREF%.BL.y=%%Y+%%[fx:int(%F4Csub.y%+%subSemiH%+0.5)]" ^
  %QUARTERS%[2]`) do set /A %%L

set %ENV_PREF%.BL.BAD=%F4Csub.BAD%


:: Create a debugging image

if not "%OUTFILE%"=="" call %PICTBAT%drawCircs ^
  %INFILE% ^
  %OUTFILE% ^
  %dcPARAMS% ^
  %ENV_PREF%.TL %ENV_PREF%.TR %ENV_PREF%.BL %ENV_PREF%.BR

set %ENV_PREF%.

set ENV_LIST=%BASENAME%_f4csEnv.lis
set %ENV_PREF% >%ENV_LIST%

call echoRestore

@endlocal & for /F %%L in (%ENV_LIST%) do @set %%L

find4cornEdgeBlr.bat

rem Given %1 is image, whitish quadrangle on blackish background,
rem finds the four corners by blurred edges.
rem Writes enviroment variable prefix %2
rem and output image %3.
rem %4 is three (quoted) parameters for drawCircs.bat: colour, radius, strokewidth.


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

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 f4ceb


set ENV_PREF=%2
if "%ENV_PREF%"=="." set ENV_PREF=
if "%ENV_PREF%"=="" set ENV_PREF=f4cebENV

set OUTFILE=%3
if "%OUTFILE%"=="." set OUTFILE=
if /I "%OUTFILE%"=="NULL:" set OUTFILE=

set dcPARAMS=%~4
if "%dcPARAMS%"=="." set dcPARAMS=
if "%dcPARAMS%"=="" set dcPARAMS=. . .

set TMP_FILE=%BASENAME%_f4ceb.miff

call %PICTBAT%slopeMag %INFILE% %TMP_FILE%

set nFnd=0
for /F "usebackq tokens=1-4 delims=, " %%A in (`%IMDEV%convert ^
  %TMP_FILE% ^
  -blur 0x5 ^
  -crop 2x2@ ^
  -format "offs: %%s %%X,%%Y\n"
  +write info: ^
  -process midlightest ^
  NULL: 2^>^&1`) do (
  rem echo %%A %%B %%C %%D
  if "%%A"=="offs:" (
    set /A C[%%B].offsX=%%C
    set /A C[%%B].offsY=%%D
  ) else (
    set C[!nFnd!].x=%%A
    set C[!nFnd!].y=%%B
    set /A nFnd+=1
  )
)

if not %nFnd%==4 exit /B 1

for /L %%I in (0,1,3) do (
  set /A C[%%I].x+=!C[%%I].offsX!
  set /A C[%%I].y+=!C[%%I].offsY!
)

rem set C[


set %ENV_PREF%.TL.x=!C[0].x!
set %ENV_PREF%.TL.y=!C[0].y!
set %ENV_PREF%.TR.x=!C[1].x!
set %ENV_PREF%.TR.y=!C[1].y!
set %ENV_PREF%.BL.x=!C[2].x!
set %ENV_PREF%.BL.y=!C[2].y!
set %ENV_PREF%.BR.x=!C[3].x!
set %ENV_PREF%.BR.y=!C[3].y!

if not "%OUTFILE%"=="" call %PICTBAT%drawCircs ^
  %INFILE% ^
  %OUTFILE% ^
  %dcPARAMS% ^
  %ENV_PREF%.TL %ENV_PREF%.TR %ENV_PREF%.BL %ENV_PREF%.BR

set %ENV_PREF%.

set ENV_LIST=%BASENAME%_f4ebEnv.lis
set %ENV_PREF% >%ENV_LIST%

call echoRestore

@endlocal & for /F %%L in (%ENV_LIST%) do @set %%L

find4cornPolDist.bat

rem Given %1 is white quadrangle on black background,
rem with each quadrangle corner in corresponding quarter of the image,
rem write the four coordinate-pairs into environment variable prefix %2
rem with a polar distance method.
rem
rem Also creates debugging output %3. Blank or . or NULL: for no output image.
rem %4 is 0 (don't trim first) or 1 (do trim first). Default 1=do trim.
rem %5 is supersampling percentage, eg 300. Defalt 100=no supersampling.
rem %6 is three (quoted) parameters for drawCircs.bat: colour, radius, strokewidth.

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

@setlocal enabledelayedexpansion

rem @call echoOffSave


set INFILE=%1

set ENV_PREF=%2
if "%ENV_PREF%"=="." set ENV_PREF=
if "%ENV_PREF%"=="" set ENV_PREF=f4cENV

set OUTFILE=%3
if "%OUTFILE%"=="." set OUTFILE=
if /I "%OUTFILE%"=="NULL:" set OUTFILE=

set DO_TRIM=%4
if "%DO_TRIM%"=="." set DO_TRIM=
if "%DO_TRIM%"=="" set DO_TRIM=1

set SUPER=%5
if "%SUPER%"=="." set SUPER=
if "%SUPER%"=="" set SUPER=100

set dcPARAMS=%~6
if "%dcPARAMS%"=="." set dcPARAMS=
if "%dcPARAMS%"=="" set dcPARAMS=. . .

if %DO_TRIM%==1 (
  set sTRIM=-trim
) else (
  set sTRIM=
)

if %SUPER%==100 (
  set sSUPERSAMP=
) else (
  set sSUPERSAMP=-resize %SUPER%%%
)

set nFnd=0
for /F "usebackq tokens=1-6 delims=+x, " %%A in (`%IMDEV%convert ^
  %INFILE% ^
  -precision 19 ^
  -virtual-pixel Black ^
  -format "input: %%P%%O\n" ^
  +write info: ^
  %sTRIM% ^
  -format "trimmed: %%wx%%h%%O\n" ^
  +write info: ^
  +repage ^
  -format "semidiag: %%[fx:hypot(w,h)/2]\n" ^
  +write info: ^
  %sSUPERSAMP% ^
  -distort Depolar -1 ^
  -flip ^
  -format "unrolled: %%wx%%h\n" ^
  +write info: ^
  -crop 4x1@ ^
  -process onewhite ^
  -format "offset: %%s %%wx%%h%%O  %%wx%%h\n" ^
  info: 2^>^&1`) do (
  rem echo %%A %%B %%C %%D %%E %%F
  if "%%A"=="input:" (
    set IN_WW=%%B
    set IN_HH=%%C
    set IN_XX=%%D
    set IN_YY=%%E
  ) else if "%%A"=="trimmed:" (
    set TRM_WW=%%B
    set TRM_HH=%%C
    set TRM_XX=%%D
    set TRM_YY=%%E
  ) else if "%%A"=="semidiag:" (
    set SEMIDIAG=%%B
  ) else if "%%A"=="unrolled:" (
    set UNR_WW=%%B
    set UNR_HH=%%C
  ) else if "%%A"=="offset:" (
    set OFFS[%%B].WW=%%C
    set OFFS[%%B].HH=%%D
    set OFFS[%%B].XX=%%E
    set OFFS[%%B].YY=%%F
  ) else if "%%A"=="onewhite:" (
    set POL[!nFnd!].x=%%B
    set POL[!nFnd!].y=%%C
    set /A nFnd+=1
  )
)

if not "%nFnd%"=="4" exit /B 1

rem set POL
rem set OFFS
rem set TRM_

for /L %%I in (0,1,3) do (
  call :doCalc theta "(!POL[%%I].x!+!OFFS[%%I].XX!)*2*pi/%UNR_WW%"
  call :doCalc rad "(1-!POL[%%I].y!/%UNR_HH%)*%SEMIDIAG%"

  call :doCalc C[%%I].x "%TRM_WW%/2-!rad!*sin(!theta!)+%TRM_XX%"
  call :doCalc C[%%I].y "%TRM_HH%/2-!rad!*cos(!theta!)+%TRM_YY%"

  rem echo theta=!theta! rad=!rad! x=!C[%%I].x! y=!C[%%I].y!
)


if not "%OUTFILE%"=="" call %PICTBAT%drawCircs %INFILE% %OUTFILE% %dcPARAMS% C[0] C[1] C[2] C[3]

set %ENV_PREF%.TL.x=%C[0].x%
set %ENV_PREF%.TL.y=%C[0].y%
set %ENV_PREF%.BL.x=%C[1].x%
set %ENV_PREF%.BL.y=%C[1].y%
set %ENV_PREF%.BR.x=%C[2].x%
set %ENV_PREF%.BR.y=%C[2].y%
set %ENV_PREF%.TR.x=%C[3].x%
set %ENV_PREF%.TR.y=%C[3].y%

set ENV_LIST=%BASENAME%_f4cpdEnv.lis
set %ENV_PREF% >%ENV_LIST%

call echoRestore

@endlocal & for /F %%L in (%ENV_LIST%) do @set %%L

@exit /B 0

::----------------------------------------------------
:: Subroutine

:doCalc
set %1=
for /F "usebackq" %%L in (`%IM%identify -precision 19 -format "%1=%%[fx:%~2]" xc:`) do set %%L

rem echo %1 is !%1!

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

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 find4corn.h1. To re-create this web page, run "procH1 find4corn".


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 9-July-2016.

Page created 04-Aug-2016 13:35:08.

Copyright © 2016 Alan Gibson.