For translating the perspective transform, here is the proper way to preserve the transform from the 4 corner control point pairs AND shift (translate) the result.
1) compute and save the perspective projection coefficients by using -verbose with +distort perspective and 4 corner control point pairs
2) project the input dot location to its corresponding output dot location using the projection coefficients (px,py)
3) compute the x and y offsets (delta) for the translation using the desired location (dx,dy) and projected location (px,py) as del=(desired - projected)
4) modify the projection coefficients to take into account the translation
This can be done using:
delx = dx - (sx*Xs + ry*Ys + tx)/(px*Xs + py*Ys + 1.0)
dely = dy - (rx*Xs + sy*Ys + ty)/(px*Xs + py*Ys + 1.0)
where dx,dy are the desired dot locations after translation and the perspective equation which computes px,py is from
http://www.imagemagick.org/Usage/distor ... projection We rewrite the equation to solve for dx,dy and then multiply the denominator by delx,dely and combine terms for Xs, Ys and the constant term.
From the above we find that the new coefficients are:
sxn=sx+delx*px
ryn=ry+delx*py
txn=tx+delx
rxn=rx+dely*px
syn=sy+dely*py
tyn=ty+dely
So given the two input images:
And the dot locations of red dot at sx,sy=59,26 and blue target dot at dx,dy=52,30 (along with the four corresponding corner coordinates), then the following script produces the steps above:
Code: Select all
pair1="0,0 3,5"
pair2="100,0 101,0"
pair3="100,75 96,85"
pair4="0,75 3,67"
sx=59
sy=26
dx=52
dy=30
clist=`convert 2e6fxqq.png -verbose -define distort:viewport=1x1+0+0 \
+distort perspective "$pair1 $pair2 $pair3 $pair4" null: 2>&1 \
| sed -n '3,4 p' | tr "'" "\000" | tr "," " "`
cArr=($clist)
c1=${cArr[0]}
c2=${cArr[1]}
c3=${cArr[2]}
c4=${cArr[3]}
c5=${cArr[4]}
c6=${cArr[5]}
c7=${cArr[6]}
c8=${cArr[7]}
px=`convert xc: -format "%[fx:($c1*$sx+$c2*$sy+$c3)/($c7*$sx+$c8*$sy+1)]" info:`
py=`convert xc: -format "%[fx:($c4*$sx+$c5*$sy+$c6)/($c7*$sx+$c8*$sy+1)]" info:`
delx=`convert xc: -format "%[fx:$dx-$px]" info:`
dely=`convert xc: -format "%[fx:$dy-$py]" info:`
cn1=`convert xc: -format "%[fx:$c1+$delx*$c7]" info:`
cn2=`convert xc: -format "%[fx:$c2+$delx*$c8]" info:`
cn3=`convert xc: -format "%[fx:$c3+$delx]" info:`
cn4=`convert xc: -format "%[fx:$c4+$dely*$c7]" info:`
cn5=`convert xc: -format "%[fx:$c5+$dely*$c8]" info:`
cn6=`convert xc: -format "%[fx:$c6+$dely]" info:`
convert 1231g8z.png \
\( 2e6fxqq.png -alpha set -virtual-pixel transparent +distort perspectiveprojection "$cn1 $cn2 $cn3 $cn4 $cn5 $cn6 $c7 $c8" \) \
-compose multiply -flatten 1and2_flatten1.png
Now if we want the blue dot to be shifted 10 more pixels in x and y to dx=62 and dy=40, the we use:
Code: Select all
pair1="0,0 3,5"
pair2="100,0 101,0"
pair3="100,75 96,85"
pair4="0,75 3,67"
sx=59
sy=26
dx=62
dy=40
clist=`convert 2e6fxqq.png -verbose -define distort:viewport=1x1+0+0 \
+distort perspective "$pair1 $pair2 $pair3 $pair4" null: 2>&1 \
| sed -n '3,4 p' | tr "'" "\000" | tr "," " "`
cArr=($clist)
c1=${cArr[0]}
c2=${cArr[1]}
c3=${cArr[2]}
c4=${cArr[3]}
c5=${cArr[4]}
c6=${cArr[5]}
c7=${cArr[6]}
c8=${cArr[7]}
px=`convert xc: -format "%[fx:($c1*$sx+$c2*$sy+$c3)/($c7*$sx+$c8*$sy+1)]" info:`
py=`convert xc: -format "%[fx:($c4*$sx+$c5*$sy+$c6)/($c7*$sx+$c8*$sy+1)]" info:`
delx=`convert xc: -format "%[fx:$dx-$px]" info:`
dely=`convert xc: -format "%[fx:$dy-$py]" info:`
cn1=`convert xc: -format "%[fx:$c1+$delx*$c7]" info:`
cn2=`convert xc: -format "%[fx:$c2+$delx*$c8]" info:`
cn3=`convert xc: -format "%[fx:$c3+$delx]" info:`
cn4=`convert xc: -format "%[fx:$c4+$dely*$c7]" info:`
cn5=`convert xc: -format "%[fx:$c5+$dely*$c8]" info:`
cn6=`convert xc: -format "%[fx:$c6+$dely]" info:`
convert 1231g8z.png \
\( 2e6fxqq.png -alpha set -virtual-pixel transparent +distort perspectiveprojection "$cn1 $cn2 $cn3 $cn4 $cn5 $cn6 $c7 $c8" \) \
-compose multiply -flatten 1and2_flatten2.png
Use -layers merge in stead of -flatten if you don't want the projected red quadrilateral to be cropped by the size of the blue background image during the compositing (for example if dx and dy were shifted by 30 either way, positive or negative, rather than by +10). That way the canvas expands to hold it all.as per Anthony's comments above.