snibgo's ImageMagick pages

Pin or push

We can push pixels to new locations while pinning others in place.

This page does not consider how the user might specify the displacement. A trimap can specify which pixels are pinned, or pushed to new locations, or are free to move or not. I can't see an elegant graphical method for specifying new locations for pushed pixels. This could be simple text coordinates, of course.

Sample inputs

We demonstrate with a photograph that has an overlaid grid.

goto :eof

call %PICTBAT%gridOver ^
  toes.png pop_src.png 10 10

set SRC=pop_src.png
pop_src.pngjpg

We also make an identity absolute displacement map.

set IDENT=^
0,0,#000,^
%%[fx:w-1],0,#f00,^
0,%%[fx:h-1],#0f0,^
%%[fx:w-1],%%[fx:h-1],#ff0

%IM%convert ^
  %SRC% ^
  -strip ^
  -sparse-color bilinear "%IDENT%" ^
  pop_id_abs_map.png
pop_id_abs_map.pngjpg

On this page, ordinary absolute displacement maps are called "pull" maps, because the value at a pixel in the map determines where the corresponding pixel in the final image comes from. We use the process module invdispmap to invert the map, making a "push" map, which determines where the corresponding pixel in the final image will be pushed to. The process invdispmap also does the opposite, converting a push map into a pull map. The inversion process leaves holes that we fill by relaxation.

The identity absolute displacement map creates no displacement, so can be regarded as either a pull map or a push map.

Move points

We first consider a special case: we move coordinate (x1,y1) to (x2,y2), by moving an entire column from x1 to x2, and an entire row from y1 to y2. All other pixels should move in a "reasonable" way. Pixels at the top and bottom edge will move left or right. Pixels at the left or right edge will move up or down. Corner pixels won't move at all.

set X1=100
set Y1=100
set X2=130
set Y2=120

Linear interpolation

We can crop into two pieces horizontally at X1, then resize each, and append them together. Then we do the same vertically.

set sFMT=^
WW=%%w\n^
HH=%%h\n^
WR1=%%[fx:w-%X1%]\n^
WR2=%%[fx:w-%X2%]\n^
HB1=%%[fx:h-%Y1%]\n^
HB2=%%[fx:h-%Y2%]

for /F "usebackq" %%L in (`%IM%identify ^
  -format "%sFMT%"
  %SRC%`) do set %%L

%IM%convert ^
  %SRC% ^
  ( -clone 0 ^
    -crop %X1%x+0+0 +repage ^
    -resize "%X2%x^!" ^
  ) ^
  ( -clone 0 ^
    -crop %WR1%x+%X1%+0 +repage ^
    -resize "%WR2%x^!" ^
  ) ^
  -delete 0 ^
  +append ^
  ( -clone 0 ^
    -crop x%Y1%+0+0 +repage ^
    -resize "x%Y2%^!" ^
  ) ^
  ( -clone 0 ^
    -crop x%HB1%+0+%Y1% +repage ^
    -resize "x%HB2%^!" ^
  ) ^
  -delete 0 ^
  -append ^
  pop_li1.png
pop_li1.pngjpg

The abrupt change of scale is obvious.

Power curve

A single point can be moved by applying a power (gamma) function to the gradients of the identity map. This is a pull map, so the value at coordinate (x2,y2) should be x1 in the red channel and y1 in the green channel.

We raise to the power k such that:

v' = v^k

log(v') = log(v^k)  (where log is to any base)
        = k * log(v)

k = log(v') / log(v)

We use v7, so the calculation can be done within the "-evaluate pow".

Make a displacement map.

%IMG7%magick ^
  pop_id_abs_map.png ^
  -channel R ^
  -evaluate pow %%[fx:log(%X1%/(w-1))/log(%X2%/(w-1))] ^
  -channel G ^
  -evaluate pow %%[fx:log(%Y1%/(h-1))/log(%Y2%/(h-1))] ^
  +channel ^
  pop_pc_map.png
pop_pc_map.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pc_map.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pc1.png
pop_pc1.pngjpg

There is no abrupt change of scale, but stretching at the left and top edges is severe.

Pushing multiple points

Iterating the above won't move multiple points, because moving any one point uniquely determines the movement of all the others. A power (gamma) curve is determined by a single point.

The obvious solution is a Bézier curve, which is determined by however many points we want. An external program, cBezCurve.exe, calculates values along a Bézier curve, creating an Nx1 clut image. We use this twice, for the two dimensions.

(I don't publish the source or binary of cBezCurve.exe. The program calculates "reasonable" coordinates for the required extra control points.)

Get the dimensions.

for /F "usebackq" %%L in (`%IM%identify ^
  -format "WW=%%w\nHH=%%h\nWm1=%%[fx:w-1]\nHm1=%%[fx:h-1]" ^
  %SRC%`) do set %%L

echo WW=%WW% HH=%HH% 
WW=267 HH=233 

Make a WWx1 clut for the horizontal displacement. This is really a slightly distorted gradient. At ordinate X2, we want value X1. We also pin the first and last ordinates, 0 and %Wm1%.

cBezCurve /p0 /C /a1 /m%Wm1% /I"0,0; %X2%,%X1%; %Wm1%,%Wm1%" /n%WW% /T1 /F0 /Lpop_dx.ppm

Similarly, a HHx1 clut for the vertical displacement.

cBezCurve /p0 /C /a1 /m%Hm1% /I"0,0; %Y2%,%Y1%; %Hm1%,%Hm1%" /n%HH% /T1 /F0 /Lpop_dy.ppm

Use these two cluts to make a displacement map. We have told cBezCurve.exe to create just the red channel, so combining them is slightly complex. We need the red channel of the first PPM to go into the red channel of the map, and red channel of the second PPM to go into the green channel of the map.

Make a displacement map.

%IM%convert ^
  pop_dx.ppm ^
  ( pop_dy.ppm -rotate 90 ) ^
  xc:Black ^
  -channel R ^
  -scale "%WW%x%HH%^!" ^
  -separate ^
  +channel ^
  -combine ^
  pop_pmp_map.png
pop_pmp_map.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pmp_map.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pmp1.png
pop_pmp1.pngjpg

The result is similar to the one from the power (gamma) curve, but with less severe stretching at the left and top edges.

cBezCurve.exe has other interpolation methods, such as linear:

cBezCurve /p0 /C /a1 /m%Wm1% /I"0,0; %X2%,%X1%; %Wm1%,%Wm1%" /n%WW% /T0 /F0 /Lpop_dx1a.ppm

cBezCurve /p0 /C /a1 /m%Hm1% /I"0,0; %Y2%,%Y1%; %Hm1%,%Hm1%" /n%HH% /T0 /F0 /Lpop_dy1a.ppm

Make a displacement map.

%IM%convert ^
  pop_dx1a.ppm ^
  ( pop_dy1a.ppm -rotate 90 ) ^
  xc:Black ^
  -channel R ^
  -scale "%WW%x%HH%^!" ^
  -separate ^
  +channel ^
  -combine ^
  pop_pmp_map1a.png
pop_pmp_map1a.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pmp_map1a.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pmp1a.png

The result is essentially the same as the crop-resize method above.

pop_pmp1a.pngjpg

With Bézier curves, we can push as many pixels as we like. Morever, the same mechanism can pin pixels; we simply give the same coordinates for input and output.

set pinX=30
set pinY=25

set X3=50
set Y3=200
set X4=55
set Y4=185

set X5=200
set Y5=50
set X6=210
set Y6=60

set NewX=%pinX%,%pinX%; %X4%,%X3%; %X6%,%X5%

set NewY=%pinY%,%pinY%; %Y4%,%Y3%; %Y6%,%Y5%

Make the cluts:

cBezCurve /p0 /C /a1 /m%Wm1% /I"0,0; %X2%,%X1%; %NewX%; %Wm1%,%Wm1%" /n%WW% /T1 /F0 /Lpop_dx2.ppm

cBezCurve /p0 /C /a1 /m%Hm1% /I"0,0; %Y2%,%Y1%; %NewY%; %Hm1%,%Hm1%" /n%HH% /T1 /F0 /Lpop_dy2.ppm

Make a displacement map.

%IM%convert ^
  pop_dx2.ppm ^
  ( pop_dy2.ppm -rotate 90 ) ^
  xc:Black ^
  -channel R ^
  -scale "%WW%x%HH%^!" ^
  -separate ^
  +channel ^
  -combine ^
  pop_pmp_map2.png
pop_pmp_map2.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pmp_map2.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pmp2.png
pop_pmp2.pngjpg

When we move X1,Y1 to X2,Y2, all pixels on row Y1 will move to row Y2, and all pixels on column X1 will move to column X2. Hence, input lines that were vertical or horizontal will be vertical or horizontal in the output.

We could invert the map, getting a push (instead of pull) map. This could be modulated, eg reduced except in the vicinity of points, and converted back to a pull map. For example, we modulate with a gradient so we have no displacement at the top:

Invert, to get a push map.

%IMDEV%convert ^
  pop_pmp_map2.png ^
  -process invdispmap ^
  pop_pmp_map2i.png
pop_pmp_map2i.png

Fill by relaxation.

set rfCOMP_METRIC=PAE
set THRESH=1e-4
set NUM_ITER=1000

call %PICTBAT%relaxFillMS ^
  pop_pmp_map2i.png . pop_pmp_maprf.png %THRESH% %NUM_ITER%

We will use this push map a few times.

pop_pmp_maprf.pngjpg

Blend with identity map, to get zero displacement at the top and full displacement at the bottom.

%IM%convert ^
  pop_pmp_maprf.png ^
  pop_id_abs_map.png ^
  -size %WW%x%HH% gradient: ^
  -compose Over -composite ^
  pop_pmp_mapbld.png
pop_pmp_mapbld.pngjpg

Invert, to get a pull map.

%IMDEV%convert ^
  pop_pmp_mapbld.png ^
  -process invdispmap ^
  pop_pmp_mapbldi.png
pop_pmp_mapbldi.png

Fill by relaxation.

call %PICTBAT%relaxFillMS ^
  pop_pmp_mapbldi.png . pop_pmp_mapbirf.png %THRESH% %NUM_ITER%
pop_pmp_mapbirf.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pmp_mapbirf.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pmp_bld.png
pop_pmp_bld.pngjpg

In the next example, we get the full displacement at the required points, and decreasing displacement further from any points. We are modifying the push map, so we want a mask that is black at the original locations of pinned or pushed pixels.

Black where we have a point; otherwise white.

%IM%convert ^
  -size %WW%x%HH% ^
  xc:White ^
  -fill Black ^
  -draw "point %pinX%,%pinY% point %X1%,%Y1% point %X3%,%Y3% point %X5%,%Y5% " ^
  pop_pnt_mask.png
pop_pnt_mask.png
%IM%convert ^
  pop_pnt_mask.png ^
  -morphology Distance Euclidean:7,100 ^
  -auto-level ^
  pop_pnt_mask2.png
pop_pnt_mask2.pngjpg

Blend with identity map.

%IM%convert ^
  pop_pmp_maprf.png ^
  pop_id_abs_map.png ^
  pop_pnt_mask2.png ^
  -compose Over -composite ^
  pop_pmp_mapbld2.png
pop_pmp_mapbld2.pngjpg

Invert, to get a pull map.

%IMDEV%convert ^
  pop_pmp_mapbld2.png ^
  -process invdispmap ^
  pop_pmp_mapbld2i.png
pop_pmp_mapbld2i.png

Fill by relaxation.

call %PICTBAT%relaxFillMS ^
  pop_pmp_mapbld2i.png . pop_pmp_maprf2.png %THRESH% %NUM_ITER%
pop_pmp_maprf2.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pmp_maprf2.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pmp_bld2.png
pop_pmp_bld2.pngjpg

Another possibility: apply the full effect only in a circle around each point. The radius at each point probably needs to be sufficient to cover the displacement. For simplicity, we use the same radius and blur for all the circles.

Draw circles, and blur them.

set sCIRC=circle 0,0 0,60

%IM%convert ^
  -size %WW%x%HH% ^
  xc:White ^
  -fill Black ^
  -draw "translate %pinX%,%pinY% %sCIRC%" ^
  -draw "translate %X1%,%Y1% %sCIRC%" ^
  -draw "translate %X3%,%Y3% %sCIRC%" ^
  -draw "translate %X5%,%Y5% %sCIRC%" ^
  -blur 0x25 ^
  pop_pnt_mask3.png
pop_pnt_mask3.pngjpg

Blend with identity map.

%IM%convert ^
  pop_pmp_maprf.png ^
  pop_id_abs_map.png ^
  pop_pnt_mask3.png ^
  -compose Over -composite ^
  pop_pmp_mapbld3.png
pop_pmp_mapbld3.pngjpg

Invert, to get a pull map.

%IMDEV%convert ^
  pop_pmp_mapbld3.png ^
  -process invdispmap ^
  pop_pmp_mapbld3i.png
pop_pmp_mapbld3i.png

Fill by relaxation.

call %PICTBAT%relaxFillMS ^
  pop_pmp_mapbld3i.png . pop_pmp_maprf3.png %THRESH% %NUM_ITER%
pop_pmp_maprf3.pngjpg

Apply the map.

%IM%convert ^
  %SRC% ^
  pop_pmp_maprf3.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_pmp_bld3.png
pop_pmp_bld3.pngjpg

Move areas

Above, we have pinned or pushed individual pixels. (Strictly speaking, individual coordinates.) Instead, we can pin or push groups of pixels. All the pixels in each group will be displaced by the same amount. The method shown here is in general quite complex, but simple enough when each area is a rectangle (so this also includes horizontal and vertical lines).

The method is to either construct an identity absolute displacement map and move the areas, making the other pixels transparent, or to make a relative displacement map with areas of the appropriate shade of gray.

Each pixel in the displacement map is one of:

Transparent pixels in the displacement map are then filled by the relaxation method, and the map is used to displace the input image.

Absolute displacement maps

IM v6 can't have %[fx:] in -crop, so we use v7. For the edges of the map, early versions of v7 don't have "-region" so we do the job with four crops.

set sEDGES=^
  ( -clone 0 -crop %%[fx:w]x1+0+0 ) ^
  ( -clone 0 -crop %%[fx:w]x1+0+%%[fx:h-1] ) ^
  ( -clone 0 -crop 1x%%[fx:h]+0+0 ) ^
  ( -clone 0 -crop 1x%%[fx:h]+%%[fx:w-1]+0 )
%IMG7%magick ^
  pop_id_abs_map.png ^
  ( -clone 0 -alpha transparent ) ^
  %sEDGES% ^
  ( -clone 0 ^
    -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^
  ) ^
  -delete 0 ^
  -background None ^
  -layers flatten ^
  pop_map1.png
pop_map1.png
set rfCOMP_METRIC=PAE
set THRESH=1e-4
set NUM_ITER=1000

rem set rfCOMP_METRIC=RMSE
rem set THRESH=1e-6

call %PICTBAT%relaxFillMS ^
  pop_map1.png . . %THRESH% %NUM_ITER%
pop_map1_rfms.pngjpg

We should have no displacement:

%IM%convert ^
  %SRC% ^
  pop_map1_rfms.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_m1.png
pop_m1.pngjpg

Displace a central block:

%IMG7%magick ^
  pop_id_abs_map.png ^
  ( -clone 0 -alpha transparent ) ^
  %sEDGES% ^
  ( -clone 0 ^
    -set DW %%[fx:w*0.1] ^
    -set DH %%[fx:h*0.1] ^
    -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^
    -repage "+%%[DW]+%%[DH]^!" ^
  ) ^
  -delete 0 ^
  -background None ^
  -layers flatten ^
  pop_map2.png
pop_map2.png
call %PICTBAT%relaxFillMS ^
  pop_map2.png . . %THRESH% %NUM_ITER%
pop_map2_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_map2_rfms.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_m2.png
pop_m2.pngjpg

Displace the four corners of a central block:

set sREPAGE=-repage "+%%[DW]+%%[DH]^^^!"

%IMG7%magick ^
  pop_id_abs_map.png ^
  -set DW %%[fx:w*0.1] ^
  -set DH %%[fx:h*0.1] ^
  ( -clone 0 -alpha transparent ) ^
  %sEDGES% ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.4] ^
    %sREPAGE% ^
  ) ^
  ( -clone 0 ^
  -set DW %%[fx:w*0.1] ^
  -set DH %%[fx:h*0.1] ^
    -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.4] ^
    %sREPAGE% ^
  ) ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.6] ^
    %sREPAGE% ^
  ) ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.6] ^
    %sREPAGE% ^
  ) ^
  -delete 0 ^
  -background None ^
  -layers flatten ^
  pop_map3.png
pop_map3.png
call %PICTBAT%relaxFillMS ^
  pop_map3.png . . %THRESH% %NUM_ITER%
pop_map3_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_map3_rfms.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_m3.png
pop_m3.pngjpg

The displacement is not as far as we wanted. Repeat the previous, but without multi-scale:

call %PICTBAT%relaxFill ^
  pop_map3.png . pop_map3a_rfms.png ^
 %THRESH% %NUM_ITER%
pop_map3a_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_map3a_rfms.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_m3a.png
pop_m3a.pngjpg

This hasn't cured the problem.

Sadly, the process doesn't work well when we have isolated pixels in the holed image. The pixel at (50%,50%) has the correct value of RG=(40%,40%), but moving away from this pixel, the values swiftly rise.

Try moving small squares, one at each location:

set rfCOMP_METRIC=PAE
set THRESH=1e-4
set NUM_ITER=1000

set sREPAGE=-repage "+%%[DW]+%%[DH]^^^!"

set SW=10
set SH=10

%IMG7%magick ^
  pop_id_abs_map.png ^
  -set DW %%[fx:w*0.1] ^
  -set DH %%[fx:h*0.1] ^
  ( -clone 0 -alpha transparent ) ^
  %sEDGES% ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.4]+%%[fx:h*0.4] ^
    %sREPAGE% ^
  ) ^
  ( -clone 0 ^
  -set DW %%[fx:w*0.1] ^
  -set DH %%[fx:h*0.1] ^
    -crop %SW%x%SH%+%%[fx:w*0.7]+%%[fx:h*0.4] ^
    %sREPAGE% ^
  ) ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.4]+%%[fx:h*0.6] ^
    %sREPAGE% ^
  ) ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.7]+%%[fx:h*0.6] ^
    %sREPAGE% ^
  ) ^
  -delete 0 ^
  -background None ^
  -layers flatten ^
  pop_map4.png
pop_map4.png
call %PICTBAT%relaxFillMS ^
  pop_map4.png . . %THRESH% %NUM_ITER%
pop_map4_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_map4_rfms.png ^
  -compose Distort -set option:compose:args 100%%x100%% -composite ^
  pop_m4.png
pop_m4.pngjpg

Relative displacement maps

Relative displacement maps are simpler, as each rectangle is a constant shade of gray.

%IMG7%magick ^
  %SRC% ^
  -shave 1x1 ^
  -alpha transparent ^
  -bordercolor gray(50%%) -border 1 ^
  -set page %%[fx:w*0.4]+%%[fx:h*0.4] ^
  ( -clone 0 ^
    -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^
    -alpha opaque ^
    -fill gray(50%%) -colorize 100 ^
  ) ^
  -background None ^
  -layers merge ^
  pop_rmap1.png
pop_rmap1.png
set rfCOMP_METRIC=PAE
set THRESH=1e-4
set NUM_ITER=1000

rem set rfCOMP_METRIC=RMSE
rem set THRESH=1e-6

call %PICTBAT%relaxFillMS ^
  pop_rmap1.png . . %THRESH% %NUM_ITER%
pop_rmap1_rfms.pngjpg

We should have no displacement:

%IM%convert ^
  %SRC% ^
  pop_rmap1_rfms.png ^
  -compose Displace -set option:compose:args 100%%x100%% -composite ^
  pop_rm1.png
pop_rm1.pngjpg

Displace a central block:

%IMG7%magick ^
  %SRC% ^
  -shave 1x1 ^
  -alpha transparent ^
  -bordercolor gray(50%%) -border 1 ^
  -set page %%[fx:w*0.4]+%%[fx:h*0.4] ^
  ( -clone 0 ^
    -crop %%[fx:w*0.3]x%%[fx:h*0.2]+%%[fx:w*0.4]+%%[fx:h*0.4] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  -background None ^
  -layers merge ^
  pop_rmap2.png
pop_rmap2.png
call %PICTBAT%relaxFillMS ^
  pop_rmap2.png . . %THRESH% %NUM_ITER%
pop_rmap2_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_rmap2_rfms.png ^
  -compose Displace -set option:compose:args 100%%x100%% -composite ^
  pop_rm2.png
pop_rm2.pngjpg

Displace the four corners of a central block:

%IMG7%magick ^
  %SRC% ^
  -shave 1x1 ^
  -alpha transparent ^
  -bordercolor gray(50%%) -border 1 ^
  -set page %%[fx:w*0.4]+%%[fx:h*0.4] ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.4] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.4] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.4]+%%[fx:h*0.6] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  ( -clone 0 ^
    -crop 1x1+%%[fx:w*0.7]+%%[fx:h*0.6] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  -background None ^
  -layers merge ^
  pop_rmap3.png
pop_rmap3.png
call %PICTBAT%relaxFillMS ^
  pop_rmap3.png . . %THRESH% %NUM_ITER%
pop_rmap3_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_rmap3_rfms.png ^
  -compose Displace -set option:compose:args 100%%x100%% -composite ^
  pop_rm3.png
pop_rm3.pngjpg

Again, this doesn't work well. Try larger rectangles.

set SW=10
set SH=10

%IMG7%magick ^
  %SRC% ^
  -shave 1x1 ^
  -alpha transparent ^
  -bordercolor gray(50%%) -border 1 ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.5]+%%[fx:h*0.5] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.8]+%%[fx:h*0.5] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.5]+%%[fx:h*0.7] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  ( -clone 0 ^
    -crop %SW%x%SH%+%%[fx:w*0.8]+%%[fx:h*0.7] ^
    -alpha opaque ^
    -fill gray(40%%) -colorize 100 ^
  ) ^
  -background None ^
+write info: ^
  -layers merge ^
  pop_rmap4.png
pop_rmap4.png
set rfCOMP_METRIC=PAE
set THRESH=1e-4
set NUM_ITER=1000

call %PICTBAT%relaxFillMS ^
  pop_rmap4.png . . %THRESH% %NUM_ITER%
pop_rmap4_rfms.pngjpg
%IM%convert ^
  %SRC% ^
  pop_rmap4_rfms.png ^
  -compose Displace -set option:compose:args 100%%x100%% -composite ^
  pop_rm4.png
pop_rm4.pngjpg

Future

It would be cute to allow constrained movement. For example, we might allow pixels at the left and right sides to move vertically but not horizontally.


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


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 18-November-2016.

Page created 30-Nov-2016 07:19:43.

Copyright © 2016 Alan Gibson.