#!/bin/bash
# 
# Developed by Fred Weinhaus 7/16/2018 .......... revised 11/26/2023
# 
# ------------------------------------------------------------------------------
# 
# Licensing:
# 
# Copyright © Fred Weinhaus
# 
# My scripts are available free of charge for non-commercial use, ONLY.
# 
# For use of my scripts in commercial (for-profit) environments or 
# non-free applications, please contact me (Fred Weinhaus) for 
# licensing arrangements. My email address is fmw at alink dot net.
# 
# If you: 1) redistribute, 2) incorporate any of these scripts into other 
# free applications or 3) reprogram them in another scripting language, 
# then you must contact me for permission, especially if the result might 
# be used in a commercial or for-profit environment.
# 
# My scripts are also subject, in a subordinate manner, to the ImageMagick 
# license, which can be found at: http://www.imagemagick.org/script/license.php
# 
# ------------------------------------------------------------------------------
#
# USAGE: xtract [-p procedure] [-c coords] [-b bgcolor] [-e extend] [-t1 thresh1] 
# [-t2 thresh2] [-t3 thresh3] [-f filtsize] [-a aspect] [-w width] [-h height]  
# [-d dimension] [-s scolor] [-L linewidth] [-m mcolor] [u unrotate] [-C crop]  
# [-F fuzzval] [-R rotate] [-I info] [-S show] infile outfile
# 
# USAGE: xtract [-help]
# 
# OPTIONS:
# 
# -p     procedure     procedure (technique) for processing; choices are: deskew, 
#                      unrotate, mask or perspective; default=perspective
# -c     coords        pixel coordinate to extract background color; 
#                      may be expressed as gravity value (e.g. northwest) or 
#                      as "x,y" value; default is 0,0
# -b     bcolor		   background color outside the quadrilateral region; 
#                      any valid IM color; default determined by coords argument
# -e     extend        extend (pad) the input with background color as preprocessing 
#                      to keep corners away from bounding edges of input image; 
#                      integer>=0; default=10
# -t1    thresh1       lower Canny edge detector threshold value in percent; 
#                      0<=integer<=100; default=10
# -t2    thresh2       upper Canny edge detector threshold value in percent; 
#                      0<=integer<=100; default=75; nominal 75-90; smaller values  
#                      include more edges
# -t3    thresh3       Hough line detector threshold value in percent; 0<=integer<=100; 
#                      default=10; percent of longest dimension of input image; 
#                      too large values remove longest lines; typically 5-20%
# -f1    filtsize      Hough line detector filter size in pixels; integer>=0;  
#                      default=15; needs to be larger for larger images; typically 9-15; 
#                      larger values condense close, nearly parallel edges
# -a     aspect        desired width/height aspect ratio; float>0; or "edges" 
#                      or "points"; default=edges; used only for procedure=unperspective
#                      default will be computed automatically
# -w     width         desired width of output in pixels; integer>0; default determined 
#                      automatically from dimension parameter below;
#                      only one of width or height may be specified
# -h     height        desired height of output in pixels; integer>0; default determined 
#                      automatically from dimension parameter below;
#                      only one of width or height may be specified
# -d     dimension     output dimension method; choices are: el 
#                      (length of longest edge of quadrilaterl, bh (quadrilateral 
#                      bounding box height), bw (quadrilateral bounding box width),
#                      h (input image height), w (input image width); default=el
# -s     scolor        stroke color for showing the Hough lines on an ancillary image
#                      when -S show != none, described below; any valid IM color; 
#                      default=red
# -L     linewidth     linewidth of stroke for showing the Hough lines on an ancillary
#                      image when -S show != none, described below; integer>=0; default=2
# -m     mcolor        desired masking background color to show outside the extracted 
#                      quadrilateral when procedure=mask; any valid IM color; 
#                      default=none
# -u     unrotate      unrotate the masked result and trim to its bounding box when 
#                      procedure=mask; choices are: yes or no; default=no; 
#                      requires separate unrotate script
# -C     crop          crop (trim) the masked result (without unrotating) when 
#                      procedure=mask; choices are: yes or no; default=no
# -F     fuzzval       fuzzvalue to use to extract the background when unrotate=yes; 
#                      0<=integer<=100; default=10
# -R     rotate        rotate the image in 90 degree amounts as postprocessing; 
#                      choices are: 0, 90, 180, 270, -90; default=0
# -I     info          list various information to the terminal depending upon  
#                      procedure, including: rotation angle, crop box, aspect ratio 
#                      and/or control points used for perspective correction
# -S     show          show ancillary images for deskewed/unrotated image, 
#                      Canny edges, Hough lines superimposed on image; choices are: 
#                      none, view (to display) or save (to disk); default=none
# 
###
# 
# NAME: XTRACT 
#  
# PURPOSE: To use Hough lines to extract and rectify a quadrilateral area from an image.
# 
# DESCRIPTION: XTRACT attempts to extract and correct orientation and/or perspective in 
# an image using the Canny edge detector followed by the Hough line detector to find 
# the four sides of a quadrilateral region of an image inside a background color.
# There are four approaches that may be used. 
#
# If the image has a nearly solid color background and the quadrilateral is a  
# rectangle that is rotate by 5 degrees or less, one can use the procedure=deskew.
# 
# If the image has a nearly solid color background and the quadrilateral is a  
# rectangle that is rotate by more than 5 degrees, one can use the procedure=unrotate. 
# This will estimate the rotation angle from the orientation of longest Hough line 
# as determined by the Hough accumulator value.
#
# Otherwise, one can use procedure=unperspective to process the image. This will attempt 
# to correct the perspective distortion. However, it needs to use the aspect ratio 
# of the corrected image. One may provide the aspect ratio as a float value or let the 
# script attempt to estimate the aspect ratio. There are two approaches that may be 
# use for the estimation. One is to use the lengths of the edges of the quadrilateral  
# as determined by the Hough line intersection. The other approach is to use the 
# Hough line intersection vertices. The latter is more subject to inaccurate estimations.
# 
# Lastly, one can just mask the quadrilateral region with an option to unrotate and  
# trim the image or just trim the image to its bounding box. If unrotate=yes, then 
# my separate script, unrotate, will be needed.
#   
# The script works best when the quadrilateral area is cleanly separated by good 
# contrast from the background area and contains no very long, high contrast edges in it. 
# The three most important arguments are: thresh2, thresh3 and filtsize.
# 
# The script will error out, if fewer than 4 edges are extracted. The script will use 
# the longest 4 edges, but will error out, if other than 4 intersection points are 
# located within the bounds of the input image.
# 
# Arguments: 
# 
# 
# -p procedure ... PROCEDURE (technique) for processing. Choices are: deskew, unrotate, 
# mask or perspective. The default=perspective.
# 
# -c coords ... COORDS is any location within the input image for the algorithm to find 
# the background color. It may be specified in terms of gravity parameters 
# (NorthWest, North, NorthEast, East, SouthEast, South, SouthWest or West) or as a 
# pixel coordinate "x,y". The default is the upper left corner = NorthWest = "0,0". 
# 
# -b bcolor ... BCOLOR is the background color outside the quadrilateral region. 
# Any valid IM color is permitted. The default will be determined by the coords argument.
# 
# -e extend ... EXTEND (pad) the input with background color as a preprocessing step 
# in order to keep the corners of the quadrilateral area away from bounding edges of 
# input image. Values are integer>=0. The default=10.
# 
# -t1 thresh1 ... THRESH1 is the lower Canny edge detector threshold value in percent. 
# Values are 0<=integers<=100. The default=10.
# 
# -t2 thresh2 ... THRESH2 is the upper Canny edge detector threshold value in percent. 
# Values are 0<=integers<=100. The default=75. Typical values are in the range 75-90. 
# Smaller values will include more edges.
# 
# -t1 thresh3 ... THRESH3 is the Hough line detector threshold value in percent of 
# the longest dimension of input image converted to pixels. Values are 0<=integers<=100. 
# The default=10. Too large values remove longer lines. Typical values are in the 
# range of 5-20.
# 
# -f1 filtsize ... FILTSIZE is the Hough line detector filter size in pixels. Value are 
# integers>=0. The default=15. Values needs to be larger for larger image dimensions. 
# Typical values are in the range 9-15. Larger values condense close, nearly parallel 
# edges.
# 
# -a aspect ... ASPECT is the desired width/height aspect ratio. Values are either 
# floats>0; or "edges" or "points". The default will be computed automatically
# using the lengths of the four quadrilateral edges. Aspect is used only for 
# procedure=unperspective.
# 
# -w width ... WIDTH is the desired width of the output. The default is determined 
# automatically from the dimensions parameter below. Only one of width or height may 
# be specified. Note: the output size will only be close to the value specified.
# 
# -h height ... HEIGHT is the desired height of the output. The default is determined 
# automatically from the dimensions parameter below. Only one of width or height may 
# be specified. Note: the output size will only be close to the value specified.
# 
# -d dimensions ... DIMENSIONS specifies how to compute the output dimension. Choices 
# are: el (length of the longest edge of the quadrilateral), bh (quadrilateral
# bounding box height), bw (quadrilateral bounding box width), h (input image height), 
# or w (input image width). The default=el.
# 
# -s scolor ... SCOLOR is the stroke color used for showing the Hough lines on an 
# ancillary image when -S show != none, as described below.  Any valid IM color is 
# allowed. The default=red.
# 
# -L linewidth ... LINEWIDTH of the stroke color for showing the Hough lines on an 
# ancillary image when -S show != none, described below. Values are integers>=0. The 
# default=2.
# 
# -m mcolor ... MCOLOR is the desired masking background color to show outside the 
# extracted quadrilateral when procedure=mask. Any valid IM color is allowed.  
# The default=none.
# 
# -u unrotate ... UNROTATE the masked result and trim to its bounding box when 
# procedure=mask. The choices are: yes or no. The default=no. Note that this 
# requires my separate unrotate script.
# 
# -C  crop ... CROP (trim) the masked result (without unrotating) when procedure=mask. 
# The choices are: yes or no. The default=no.
# 
# -F fuzzval ... FUZZVAL is the fuzz value to use to extract the background when 
# unrotate=yes. Values are 0<=integers<=100. The default=10.
# 
# -R rotate ... ROTATE the output image in 90 degree amounts as a postprocessing step. 
# The choices are: 0, 90, 180, 270, -90. The default=0.
# 
# -I info ... INFO list various information to the terminal depending upon  
# procedure, including: rotation angle, crop box, aspect ratio and/or control points 
# used for the perspective correction.
# 
# -S show ... SHOW ancillary images: deskewed/unrotated image, Canny edge image, and 
# Hough lines superimposed on input image. Choices are: none, view (to display) or 
# save (to disk). The default=none.
#
# REFERENCES for aspect=points:
# http://www.sagenb.org/home/pub/704/
# http://research.microsoft.com/users/zhang/Papers/WhiteboardRectification.pdf
# http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf
# 
# REQUIREMENTS: Imagemggick 6.8.9-0 is needed by the Canny edge detector. 
# The argument -u unrotate requires my unrotate script.
# 
# CAVEAT: No guarantee that this script will work on all platforms, 
# nor that trapping of inconsistent parameters is complete and 
# foolproof. Use At Your Own Risk. 
# 
######
#

# set default values
procedure="unperspective"	# deskew, unrotate, unperspective, mask
coords="0,0"				# coords to extract background color
bcolor=""					# background color
extend=5					# extend image before processing if image too close to bounding box size
thresh1=10					# canny threshold 1
thresh2=75					# canny threshold 2 (shorter gets more edges, typically 75 to 90)
thresh3="10"				# hough threshold (pct of longest dimension of input; too large removes long edges; typically 5-20%)
filtsize=15					# hough filter size (needs to be larger for larger images (typically 9-15); larger removes nearby and nearly parallel edges)
aspect="edges"				# desired aspect ratio; float or edges or points
width=""					# desired output width
height=""					# desired output height
dimension="el"				# default dimension when width=height=""
scolor="red"				# stroke color
linewidth=2					# linewidth for stroke
mcolor="none"				# mask background color
crop="no"					# crop mask to bounding box
unrotate="no"				# unrotate and trim mask result
fuzzval=10					# unrotate fuzz value
rotate=0					# post process rotate 0, 90, 180, 270, -90 
info="no"					# list angle, cropbox, aspect, control points information
show="none"					# save, view or none
debug="false"


# set directory for temporary files
dir="."    # suggestions are dir="." or dir="/tmp"

# set up functions to report Usage and Usage with Description
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
usage1() 
	{
	echo >&2 ""
	echo >&2 "$PROGNAME:" "$@"
	sed >&2 -e '1,/^####/d;  /^###/g;  /^#/!q;  s/^#//;  s/^ //;  4,$p' "$PROGDIR/$PROGNAME"
	}
usage2() 
	{
	echo >&2 ""
	echo >&2 "$PROGNAME:" "$@"
	sed >&2 -e '1,/^####/d;  /^######/g;  /^#/!q;  s/^#*//;  s/^ //;  4,$p' "$PROGDIR/$PROGNAME"
	}

# function to report error messages
errMsg()
	{
	echo ""
	echo $1
	echo ""
	usage1
	exit 1
	}

# function to test for minus at start of value of second part of option 1 or 2
checkMinus()
	{
	test=`echo "$1" | grep -c '^-.*$'`   # returns 1 if match; 0 otherwise
    [ $test -eq 1 ] && errMsg "$errorMsg"
	}

# test for correct number of arguments and get values
if [ $# -eq 0 ]
	then
	# help information
	echo ""
	usage2
	exit 0
elif [ $# -gt 44 ]
	then
	errMsg "--- TOO MANY ARGUMENTS WERE PROVIDED ---"
else
	while [ $# -gt 0 ]
		do
		# get parameters
		case "$1" in
	     -help)    # help information
				   echo ""
				   usage2
				   ;;
			-p)    # get  procedure
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID PROCEDURE SPECIFICATION ---"
				   checkMinus "$1"
				   procedure="$1"
				   case "$procedure" in 
						deskew) procedure=deskew;;
						unrotate) procedure=unrotate;;
						unperspective) procedure=unperspective;;
						mask) procedure=mask;;
						*) errMsg "--- PROCEDURE=$procedure IS AN INVALID VALUE ---" 
					esac
				   ;;
			-c)    # coords
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID COORDS SPECIFICATION ---"
				   checkMinus "$1"
				   # further testing done later
				   ;;
			-b)    # bcolor
				   shift  # to get the next parameter
				   bcolor="$1"
				   ;;
			-e)    # extend
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID EXTEND SPECIFICATION ---"
				   checkMinus "$1"
				   extend=`expr "$1" : '\([0-9]*\)'`
				   [ "$extend" = "" ] && errMsg "--- EXTEND=$extend MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   ;;
			-t1)   # thresh1
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID THRESH1 SPECIFICATION ---"
				   checkMinus "$1"
				   thresh1=`expr "$1" : '\([0-9]*\)'`
				   [ "$thresh1" = "" ] && errMsg "--- THRESH1=$thresh1 MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$thresh1 < 0" | bc`
				   test2=`echo "$thresh1 > 100" | bc`
				   [ $test1 -eq 1 -o $test2 -eq 1 ] && errMsg "--- THRESH1=$thresh1 MUST BE A NON-NEGATIVE INTEGER BETWEEN 0 AND 100 ---"
				   ;;
			-t2)   # thresh2
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID THRESH2 SPECIFICATION ---"
				   checkMinus "$1"
				   thresh2=`expr "$1" : '\([0-9]*\)'`
				   [ "$thresh2" = "" ] && errMsg "--- THRESH2=$thresh2 MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$thresh2 < 0" | bc`
				   test2=`echo "$thresh2 > 100" | bc`
				   [ $test1 -eq 1 -o $test2 -eq 1 ] && errMsg "--- THRESH2=$thresh2 MUST BE A NON-NEGATIVE INTEGER BETWEEN 0 AND 100 ---"
				   ;;
			-t3)   # thresh3
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID THRESH3 SPECIFICATION ---"
				   checkMinus "$1"
				   thresh3=`expr "$1" : '\([0-9]*\)'`
				   [ "$thresh3" = "" ] && errMsg "--- THRESH3=$thresh3 MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$thresh3 < 0" | bc`
				   test2=`echo "$thresh3 > 100" | bc`
				   [ $test1 -eq 1 -o $test2 -eq 1 ] && errMsg "--- THRESH3=$thresh3 MUST BE A NON-NEGATIVE INTEGER BETWEEN 0 AND 100 ---"
				   ;;
			-f)    # filtsize
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID FILTSIZE SPECIFICATION ---"
				   checkMinus "$1"
				   filtsize=`expr "$1" : '\([0-9]*\)'`
				   [ "$filtsize" = "" ] && errMsg "--- FILTSIZE=$filtsize MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$filtsize == 0" | bc`
				   [ $test1 -eq 1 ] && errMsg "--- FILTSIZE=$filtsize MUST BE A POSITIVE INTEGER ---"
				   ;;
			-a)    # aspect
				   shift  # to get the next parameter
				   aspect="$1"
				   ;;
			-w)    # width
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID WIDTH SPECIFICATION ---"
				   checkMinus "$1"
				   width=`expr "$1" : '\([0-9]*\)'`
				   [ "$width" = "" ] && errMsg "--- WIDTH=$width MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$width <= 0" | bc`
				   [ $test1 -eq 1 ] && errMsg "--- WIDTH=$width MUST BE A POSITIVE INTEGER ---"
				   ;;
			-h)    # height
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID HEIGHT SPECIFICATION ---"
				   checkMinus "$1"
				   height=`expr "$1" : '\([0-9]*\)'`
				   [ "$height" = "" ] && errMsg "--- HEIGHT=$height MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$height <= 0" | bc`
				   [ $test1 -eq 1 ] && errMsg "--- HEIGHT=$height MUST BE A POSITIVE INTEGER ---"
				   ;;
			-d)    # get  dimensions
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID DIMENSIONS SPECIFICATION ---"
				   checkMinus "$1"
				   dimensions=`echo "$1" | tr "[:upper:]" "[:lower:]"`
				   case "$dimensions" in 
						el) dimensions=el;;
						bh) dimensions=bh;;
						bw) dimensions=bw;;
						h) dimensions=h;;
						w) dimensions=w;;
						*) errMsg "--- DIMENSIONS=$default IS AN INVALID VALUE ---" 
					esac
				   ;;
			-s)    # scolor
				   shift  # to get the next parameter
				   scolor="$1"
				   ;;
			-L)    # linewidth
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID LINEWIDTH SPECIFICATION ---"
				   checkMinus "$1"
				   linewidth=`expr "$1" : '\([0-9]*\)'`
				   [ "$v" = "" ] && errMsg "--- LINEWIDTH=$linewidth MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   ;;
			-m)    # mcolor
				   shift  # to get the next parameter
				   mcolor="$1"
				   ;;
			-u)    # unrotate
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID UNROTATE SPECIFICATION ---"
				   checkMinus "$1"
				   unrotate=`echo "$1" | tr "[:upper:]" "[:lower:]"`
				   case "$unrotate" in 
						yes|y) unrotate=yes;;
						no|n) unrotate=no;;
						*) errMsg "--- UNROTATE=$unrotate IS AN INVALID VALUE ---" 
					esac
				   ;;
			-C)    # crop
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID CROP SPECIFICATION ---"
				   checkMinus "$1"
				   crop=`echo "$1" | tr "[:upper:]" "[:lower:]"`
				   case "$crop" in 
						yes|y) crop=yes;;
						no|n) crop=no;;
						*) errMsg "--- CROP=$crop IS AN INVALID VALUE ---" 
					esac
				   ;;
			-F)    # fuzzval
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID FUZZVAL SPECIFICATION ---"
				   checkMinus "$1"
				   fuzzval=`expr "$1" : '\([0-9]*\)'`
				   [ "$fuzzval" = "" ] && errMsg "--- FUZZVAL=$fuzzval MUST BE A NON-NEGATIVE INTEGER (with no sign) ---"
				   test1=`echo "$fuzzval < 0" | bc`
				   test2=`echo "$fuzzval > 100" | bc`
				   [ $test1 -eq 1 -o $test2 -eq 1 ] && errMsg "--- FUZZVAL=$fuzzval MUST BE A NON-NEGATIVE INTEGER BETWEEN 0 AND 100 ---"
				   ;;
			-R)    # get  rotate
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID ROTATE SPECIFICATION ---"
				   #checkMinus "$1"
				   rotate="$1"
				   case "$rotate" in 
						0) rotate=0;;
						90) rotate=90;;
						180) rotate=180;;
						270) rotate=270;;
						-90) rotate=-90;;
						*) errMsg "--- ROTATE=$rotate IS AN INVALID VALUE ---" 
					esac
				   ;;
			-I)    # info
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID INFO SPECIFICATION ---"
				   checkMinus "$1"
				   info=`echo "$1" | tr "[:upper:]" "[:lower:]"`
				   case "$info" in 
						yes|y) info=yes;;
						no|n) info=no;;
						*) errMsg "--- INFO=$info IS AN INVALID VALUE ---" 
					esac
				   ;;
			-S)    # get  show
				   shift  # to get the next parameter
				   # test if parameter starts with minus sign 
				   errorMsg="--- INVALID SHOW SPECIFICATION ---"
				   checkMinus "$1"
				   show="$1"
				   case "$show" in 
						none|n) show=none;;
						view|v) show=view;;
						save|s) show=save;;
						*) errMsg "--- SHOW=$show IS AN INVALID VALUE ---" 
					esac
				   ;;
			 -)    # STDIN and end of arguments
				   break
				   ;;
			-*)    # any other - argument
				   errMsg "--- UNKNOWN OPTION ---"
				   ;;
			*)     # end of arguments
				   break
				   ;;
		esac
		shift   # next option
	done
	#
	# get infile and outfile
	infile="$1"
	outfile="$2"
fi

# test that infile provided
[ "$infile" = "" ] && errMsg "NO INPUT FILE SPECIFIED"

# test that outfile provided
[ "$outfile" = "" ] && errMsg "NO OUTPUT FILE SPECIFIED"

# get inname
inname=`convert -ping "$infile" -format "%t" info:`


# setup temporary images
tmpI1="$dir/XTRACT_I_$$.mpc"
tmpI2="$dir/XTRACT_I_$$.cache"
tmpD1="$dir/XTRACT_D_$$.mpc"
tmpD2="$dir/XTRACT_D_$$.cache"
tmpT1="$dir/XTRACT_T_$$.mpc"
tmpT2="$dir/XTRACT_T_$$.cache"
trap "rm -f $tmpI1 $tmpI2 $tmpD1 $tmpD2 $tmpT1 $tmpT2 ${inname}_hough.mvg ; exit 0" 0
trap "rm -f $tmpI1 $tmpI2 $tmpD1 $tmpD2 $tmpT1 $tmpT2 ${inname}_hough.mvg ; exit 1" 1 2 3 15


# use endpoints to get coeff; y=a*x+b
# substitute x1,y1 and x2,y2 into y=a*x+b and solve as:
# a=(y1-y2)/(x1-x2)
# b=y1-x1*(y1-y2)/(x1-x2)
#
# Now cast into Ax+By=C format
# -(y1-y2)*x + (x1-x2)*y = y1*(x1-x2) - x1(y1-y2)
# Thus
# A=(y2-y1)
# B=(x1-x2)
# C=y1*(x1-x2) - x1*(y1-y2)
#
# Then use Cramer's Rule for two pair of lines A1,B1,C1 and A2,B2,C2 to solve for intersection x,y
# If det=0, then lines are parallel

# function to get color at user specified location
getColor()
	{
	img="$1"
	wd=`convert -ping "$img" -format "%w" info:`
	ht=`convert -ping "$img" -format "%h" info:`
	widthm1=$((wd-1))
	heightm1=$((ht-1))
	midwidth=`echo "scale=0; $wd / 2" | bc`
	midheight=`echo "scale=0; $ht / 2" | bc`
	case "$coords" in
		NorthWest|Northwest|northwest)	coords="0,0"
										;;
						  North|north)	coords="$midwidth,0"
										;;
		NorthEast|Northeast|northeast)	coords="$widthm1,0"
										;;
							East|east)	coords="$widthm1,$midheight"
										;;
		SouthEast|Southeast|southeast)	coords="$widthm1,$heightm1"
										;;
						  South|south)	coords="$midwidth,$heightm1"
										;;
		SouthWest|Southwest|southwest)	coords="0,$heightm1"
										;;
							West|west)	coords="0,$midheight"
										;;
						[0-9]*,[0-9]*)	coords=$coords
										;;
									*)	errMsg "--- INVALID COORDS ---"
										;;
	esac
	bcolor=`convert "$img" -format "%[pixel:u.p{$coords}]" info:`
	}

# function to take pair of x,y points defining line and get A,B,C coefs
get_ABC_coefs()
	{
	p1=$1
	p2=$2
	x1=`echo "$p1" | cut -d, -f1`
	y1=`echo "$p1" | cut -d, -f2`
	x2=`echo "$p2" | cut -d, -f1`
	y2=`echo "$p2" | cut -d, -f2`
	A=`convert xc: -format "%[fx:($y2-$y1)]" info:`
	B=`convert xc: -format "%[fx:($x1-$x2)]" info:`
	C=`convert xc: -format "%[fx:($y1*($x1-$x2) - ($x1)*($y1-$y2))]" info:`
	# NOTE: bc calcs give parse errors when x or y is negative
	}
	
get_intersection()
	{
	A1=$1
	B1=$2
	C1=$3
	A2=$4
	B2=$5
	C2=$6
	if $debug; then
		echo "A1=$A1; B1=$B1; C1=$C1; A2=$A2; B2=$B2; C2=$C2;"
	fi
	det=`convert -precision 16 xc: -format "%[fx:($A1*$B2-($B1*$A2))]" info:`
	if $debug; then
		echo "det=$det;"
	fi
	test1=`convert -precision 16 xc: -format "%[fx:abs($det)>0?1:0]" info:`
	if $debug; then
		echo "test1=$test1;"
	fi
	if [ $test1 -eq 1 ]; then
	X=`convert xc: -format "%[fx:($C1*$B2-($B1*$C2))/$det]" info:`
	Y=`convert xc: -format "%[fx:($A1*$C2-($C1*$A2))/$det]" info:`
	else
	# flag as off image
	X=-123456
	Y=-123456
	fi
	if $debug; then
		echo "X=$X; Y=$Y;"
	fi
	} 

# reference: http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf
compute_aspect_ratio()
	{
	# extracted points are ordered ccw from top left
	# this subroutine wants them ordered bottom-left, bottom-right, top-left, top-right
	# center x,y is the center of the image that presumably corresponds to the focal center of the camera
	cx=`convert xc: -format "%[fx:$ww/2]" info:`
	cy=`convert xc: -format "%[fx:$hh/2]" info:`
	m1x=`echo ${ptArr[1]} | cut -d, -f1`
	m1y=`echo ${ptArr[1]} | cut -d, -f2`
	m2x=`echo ${ptArr[2]} | cut -d, -f1`
	m2y=`echo ${ptArr[2]} | cut -d, -f2`
	m3x=`echo ${ptArr[0]} | cut -d, -f1`
	m3y=`echo ${ptArr[0]} | cut -d, -f2`
	m4x=`echo ${ptArr[3]} | cut -d, -f1`
	m4y=`echo ${ptArr[3]} | cut -d, -f2`
	if $debug; then
		echo "cx=$cx; cy=$cy"
		echo "m1x=$m1x; m1y=$m1y"
		echo "m2x=$m2x; m2y=$m2y"
		echo "m3x=$m3x; m3y=$m3y"
		echo "m4x=$m4x; m4y=$m4y"
		echo ""
	fi
	# convert to proper x,y coordinates relative to center
	m1x=`convert xc: -format "%[fx:$m1x-$cx]" info:`
	m1y=`convert xc: -format "%[fx:$cy-$m1y]" info:`
	m2x=`convert xc: -format "%[fx:$m2x-$cx]" info:`
	m2y=`convert xc: -format "%[fx:$cy-$m2y]" info:`
	m3x=`convert xc: -format "%[fx:$m3x-$cx]" info:`
	m3y=`convert xc: -format "%[fx:$cy-$m3y]" info:`
	m4x=`convert xc: -format "%[fx:$m4x-$cx]" info:`
	m4y=`convert xc: -format "%[fx:$cy-$m4y]" info:`
	if $debug; then
		echo "m1x=$m1x; m1y=$m1y"
		echo "m2x=$m2x; m2y=$m2y"
		echo "m3x=$m3x; m3y=$m3y"
		echo "m4x=$m4x; m4y=$m4y"
		echo ""
	fi
	
	#simplified equations, assuming u0=0, v0=0, s=1
	k2=`echo "scale=8; (($m1y - $m4y)*$m3x - ($m1x - $m4x)*$m3y + $m1x*$m4y - ($m1y*$m4x))/(($m2y- $m4y)*$m3x - ($m2x - $m4x)*$m3y + $m2x*$m4y - ($m2y*$m4x))" | bc`
	k3=`echo "scale=8; (($m1y - $m4y)*$m2x - ($m1x - $m4x)*$m2y + $m1x*$m4y - ($m1y*$m4x))/(($m3y- $m4y)*$m2x - ($m3x - $m4x)*$m2y + $m3x*$m4y - ($m3y*$m4x))" | bc`
	ff=`echo "scale=8; (($k3*$m3y - ($m1y))*($k2*$m2y - ($m1y)) + ($k3*$m3x - ($m1x))*($k2*$m2x- ($m1x)))/(($k3 - 1)*($k2 - 1))" | bc`
	if $debug; then
		echo "k2=$k2; k3=$k3; ff=$ff;"
	fi
	if [ "$ff" = "" ]; then
		echo "--- ASPECT RATIO CANNOT BE DETERMINED ---"
	else
		# sqrt( $ff*$ff) = abs($ff)
		f=`echo "scale=5; sqrt( sqrt( $ff*$ff) )" | bc`
		aspectratio=`echo "scale=5; sqrt((($k2 - 1)^2 + ($k2*$m2y - ($m1y))^2/$f^2 + ($k2*$m2x - ($m1x))^2/$f^2)/(($k3 - 1)^2 + ($k3*$m3y - ($m1y))^2/$f^2 + ($k3*$m3x - ($m1x))^2/$f^2))" | bc`
	fi
	if $debug; then
		echo "f=$f; aspectratio=$aspectratio"
	fi
	}


# start processing

# set up for padding
if [ $extend -ne 0 ]; then
	padding="-border $extend"
else
	padding=""
fi


# get background color
if [ "$bcolor" = "" ]; then
	getColor "$infile"
fi
if $debug; then
	echo "bcolor=$bcolor;"
fi
	
# read the input image, test if valid, 
convert -quiet "$infile" -bordercolor "$bcolor" $padding +repage $tmpI1	||
	errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO size  ---"

# test to be sure that for procedure=perspective, that width, height and dimension not all empty
#[ "$procedure" = "unperspective" -a "$width" = "" -a "$height" = "" -a "$dimension" = "" ] && echo "--- WIDTH, HEIGHT AND DIMENSION MUST NOT BE EMPTY SIMULTANEOUSLY ---"


# get image width and height
WxH=`convert $tmpI1 -format "%wx%h" info:`
ww=`echo $WxH | cut -dx -f1`
hh=`echo $WxH | cut -dx -f2`
if $debug; then
	echo "ww=$ww; hh=$hh;"
fi

# convert thresh3 to pixel along longest dimension of image
thresh3=`convert xc: -format "%[fx:max($ww,$hh)*$thresh3/100]" info:`
if $debug; then
	echo "thresh3=$thresh3;"
fi

# set up for saving ancillary files
if [ "$show" != "none" ]; then
	if [ "$procedure" = "deskew" ]; then
		write1="+write ${inname}_deskew.png"
	else
		write1=""
	fi
	write2="+write ${inname}_canny.gif"
	write3="-composite ${inname}_hough.png"
else
	write1=""
	write2=""
	write3="null:"
fi

# deskewed image
if [ "$procedure" = "deskew" ]; then
	# use -deskew if angle is less than about 5 degrees
	angle=`convert $tmpI1 -colorspace gray -auto-level -background "$bcolor" -deskew 40% -format "%[deskew:angle]" info:`
	[ "$info" = "yes" ] && echo "angle=$angle;"
	convert $tmpI1 -background "$bcolor" -rotate $angle +repage $write1 $tmpD1

elif [ "$procedure" = "unrotate" ]; then
	# use angle of largest hough line with -rotate
	IFS=" "
	OLDIFS=$IFS
	IFS=$'\n'
	arr=(`convert $tmpI1 -colorspace gray -auto-level -canny 0x3+${thresh1}%+${thresh2}% \
		-hough-lines ${filtsize}x${filtsize}+${thresh3} MVG:- |\
		tail -n +3 | sort -k5,5 -n -r | head -n 1`)
	IFS=$OLDIFS
	num=${#arr[*]}
	#echo "num=$num;"
	p1=`echo ${arr[0]} | cut -d\  -f2`
	p2=`echo ${arr[0]} | cut -d\  -f3`
	#echo "$p1 $p2"
	x1=`echo "$p1" | cut -d, -f1`
	y1=`echo "$p1" | cut -d, -f2`
	x2=`echo "$p2" | cut -d, -f1`
	y2=`echo "$p2" | cut -d, -f2`
	angle=`convert xc: -format "%[fx:(180/pi)*atan(($y1-$y2)/($x1-$x2))]" info:`
	angle=`convert xc: -format "%[fx:$angle>45?(90-$angle):-$angle]" info:`
	[ "$info" = "yes" ] && echo "angle=$angle"
	convert $tmpI1 -background "$bcolor" -rotate $angle +repage $write1 $tmpD1
fi

# set up input image (original or deskewed)
if [ "$procedure" = "deskew" -o "$procedure" = "unrotate" ]; then
	img="$tmpD1"
else
	img="$tmpI1"
fi

# get dimensions of deskewed or unrotated image or original image
WxH=`convert -ping $img -format "%wx%h" info:`
WW=`echo "$WxH" | cut -dx -f1`
HH=`echo "$WxH" | cut -dx -f2`
if $debug; then
	echo "WW=$WW; HH=$HH;"
fi


# compute canny image, hough image, hough mvg file 
convert "$img" $write1 \
	\( +clone -colorspace gray -auto-level -canny 0x3+${thresh1}%+${thresh2}% $write2 \
	-background none -fill "$scolor" -stroke "$scolor" -strokewidth $linewidth \
	-hough-lines ${filtsize}x${filtsize}+${thresh3} +write ${inname}_hough.mvg \) $write3


# extract longest 4 lines
IFS=" "
OLDIFS=$IFS
IFS=$'\n'
arr=(`cat ${inname}_hough.mvg | tail -n +3 | sort -k5,5 -n -r | head -n 4`)
IFS=$OLDIFS
num=${#arr[*]}
#echo "num=$num;"
if [ $num -ne 4 ]; then
	errMsg "--- FEWER THAN 4 LINES EXTRACTED  ---"
else
	lines=""
	lineArr=()
	for ((i=0; i<num; i++)); do
	p1=`echo ${arr[$i]} | cut -d\  -f2`
	p2=`echo ${arr[$i]} | cut -d\  -f3`
	if $debug; then
		echo "$p1 $p2"
	fi
	lines="$lines line $p1 $p2"
	lineArr[$i]="$p1 $p2"
	done
	if $debug; then
		echo ""
		echo $lines
		echo ""
	fi
	if [ "$show" != "none" ]; then
		convert $img -fill "$scolor" -stroke "$scolor" -strokewidth $linewidth -draw "$lines" ${inname}_hough_longest4.png
	fi
fi


# compute all line intersections that fall inside the image
xArr=()
yArr=()
xyArr=()
k=0
for ((j=0; j<4; j++)); do
	for ((i=0; i<4; i++)); do
		if [ $i -ne $j ]; then
			p1=`echo ${lineArr[$j]} | cut -d\  -f1`
			p2=`echo ${lineArr[$j]} | cut -d\  -f2`
			if $debug; then
				echo "p1=$p1; p2=$p2"
			fi
			get_ABC_coefs "$p1" "$p2"
			A1=$A
			B1=$B
			C1=$C

			p3=`echo ${lineArr[$i]} | cut -d\  -f1`
			p4=`echo ${lineArr[$i]} | cut -d\  -f2`
			if $debug; then
				echo "p3=$p3; p4=$p4"
			fi
			get_ABC_coefs "$p3" "$p4"
			A2=$A
			B2=$B
			C2=$C
			
			get_intersection "$A1" "$B1" "$C1" "$A2" "$B2" "$C2"
			if $debug; then
				echo "X=$X; Y=$Y;"
			fi
			test2=`convert xc: -format "%[fx:($X>=0 && $X<$WW && $Y>=0 && $Y<$HH)?1:0]" info:`
			if $debug; then
				echo "test2=$test2"
				echo ""
			fi
			if [ $test2 -eq 1 ]; then
				#X=`convert xc: -format "%[fx:round($X)]" info:`
				#Y=`convert xc: -format "%[fx:round($Y)]" info:`
				X=`echo "scale=0; ($X+0.5)/1" | bc`
				Y=`echo "scale=0; ($Y+0.5)/1" | bc`
				xArr[$k]="$X"
				yArr[$k]="$Y"
				xyArr[$k]="$X,$Y"
				if $debug; then
					echo "k=$k; xArr=${xArr[$k]}; yArr=${yArr[$k]}"
				fi
				k=$((k+1))
			fi
		fi
	done
done

xnumpts=${#xArr[*]}
ynumpts=${#yArr[*]}
if $debug; then
	echo "xnumpts=$xnumpts; ynumpts=$ynumpts;"
fi
[ $xnumpts -ne 4 -o $ynumpts -ne 4 ] && errMsg "--- OTHER THAN 4 POINTS ARE LOCATED INSIDE THE IMAGE  ---"
if $debug; then
	echo "xyArr=${xyArr[*]}"
fi

# set up for postprocess rotate
if [ $rotate -ne 0 ]; then
	rotating="-rotate $rotate"
else
	rotating=""
fi

if [ "$procedure" = "deskew" -o "$procedure" = "unrotate" ]; then
	# get top left and bottom right (min,max) points
	xmax=0
	ymax=0
	xmin=1000000000000
	ymin=1000000000000
	for ((i=0; i<4; i++)); do
		[ ${xArr[$i]} -gt $xmax ] && xmax=${xArr[$i]}
		[ ${yArr[$i]} -gt $ymax ] && ymax=${yArr[$i]}
		[ ${xArr[$i]} -lt $xmin ] && xmin=${xArr[$i]}
		[ ${yArr[$i]} -lt $ymin ] && ymin=${yArr[$i]}
	done

	# get crop coords
	wd=$(($xmax-$xmin))
	ht=$(($ymax-$ymin))
	offx=$((xmin))
	offy=$((ymin))
	cropbox="${wd}x${ht}+${offx}+${offy}"
	[ "$info" = "yes" ] && echo "cropbox=$cropbox;"


	if [ "$show" != "none" ]; then
		topline="line $xmin,$ymin $xmax,$ymin"
		rightline="line $xmax,$ymin $xmax,$ymax"
		bottomline="line $xmax,$ymax $xmin,$ymax"
		leftline="line $xmin,$ymax $xmin,$ymin"
		convert $tmpD1 -fill "$scolor" -stroke "$scolor" -strokewidth $linewidth -draw "$topline $rightline $bottomline $leftline" ${inname}_cropbox.png
	fi

	# crop the image
	convert $tmpD1 -crop $cropbox +repage $rotating "$outfile"
	
elif [ "$procedure" = "unperspective" -o "$procedure" = "mask" ]; then

	# convert intersection points to polar coordinates to get the rotation relative to the x axis
	# get centroid of points first
	rotArr=()
	xcent=`convert xc: -format "%[fx:(${xArr[0]}+${xArr[1]}+${xArr[2]}+${xArr[3]})/4]" info:`
	ycent=`convert xc: -format "%[fx:(${yArr[0]}+${yArr[1]}+${yArr[2]}+${yArr[3]})/4]" info:`
	if $debug; then
		echo "xcent=$xcent; ycent=$ycent;"
		echo ""
	fi
	for ((i=0; i<4; i++)); do
		x=${xArr[$i]}
		y=${yArr[$i]}
		rot=`convert xc: -format "%[fx:(180/pi)*atan2($x-$xcent,$y-$ycent)]" info:`
		rotArr[$i]="$x,$y,$rot"
		if $debug; then
			echo "$i rotArr=${rotArr[$i]}"
		fi
	done
	
	# sort by angle
	# arctan in image coordinates goes from -180 to 0 to 180 (where the x-axis to the right and the y-axis downward)
	# zero angle is along y downward
	# so points are sorted counter-clockwise from the top left corner for a rectangle at small or no rotation
	sortlist=`echo ${rotArr[*]} | tr " " "\012" | sort -k3,3 -n -t ","`
	if $debug; then
		echo "sortlist=$sortlist"
		echo ""
	fi
	OLDIFS=$IFS
	IFS=$'\n'
	sortArr=($sortlist)
	IFS=$OLDIFS
	for ((i=0; i<4; i++)); do
		if $debug; then
			echo "$i sortArr=${sortArr[$i]}"
		fi
		xyrot="${sortArr[$i]}"
		if $debug; then
			echo "$i xyrot=$xyrot"
		fi
		xsortArr[$i]=`echo "$xyrot" | cut -d, -f1`
		ysortArr[$i]=`echo "$xyrot" | cut -d, -f2`
		ptArr[$i]="${xsortArr[$i]},${ysortArr[$i]}"
		if $debug; then
			echo "${ptArr[$i]}"
			echo ""
		fi
	done
	
	# set up for trimming of mask
	if [ "$crop" = "yes" ]; then
		trimming="-trim +repage"
	else
		trimming=""
	fi
	#echo "trimming=$trimming"
	

	if [ "$procedure" = "mask" -a "$mcolor" != "none" ]; then
		convert $tmpI1 \
			\( +clone -alpha off -fill black -colorize 100 \
			-fill white -draw "polygon ${ptArr[*]}" \) \
			-alpha off -compose copy_opacity -composite \
			-background "$mcolor" -alpha background -alpha off \
			$trimming \
			"$outfile"
		if [ "$unrotate" = "yes" ]; then
			unrotate -f $fuzzval "$outfile" "$outfile"
			[ $rotate -ne 0 ] && convert "$outfile" $rotating "$outfile"			
		fi

	elif [ "$procedure" = "mask" -a "$mcolor" = "none" ]; then
		convert $tmpI1 \
			\( +clone -alpha off -fill black -colorize 100 \
			-fill white -draw "polygon ${ptArr[*]}" \) \
			-alpha off -compose copy_opacity -composite \
			$trimming \
			"$outfile"
		if [ "$unrotate" = "yes" ]; then
			unrotate -f $fuzzval "$outfile" "$outfile"
			[ $rotate -ne 0 ] && convert "$outfile" $rotating "$outfile"			
		fi

	elif [ "$procedure" = "unperspective" ]; then

		# compute bounding box width and height from 4 intersections
		xmax=0
		ymax=0
		xmin=1000000000000
		ymin=1000000000000
		for ((i=0; i<4; i++)); do
			[ ${xArr[$i]} -gt $xmax ] && xmax=${xArr[$i]}
			[ ${yArr[$i]} -gt $ymax ] && ymax=${yArr[$i]}
			[ ${xArr[$i]} -lt $xmin ] && xmin=${xArr[$i]}
			[ ${yArr[$i]} -lt $ymin ] && ymin=${yArr[$i]}
		done

		# get crop coords
		wd=$(($xmax-$xmin))
		ht=$(($ymax-$ymin))
		if $debug; then
			echo "xmax=$xmax; ymax=$ymax; xmin=$xmin; ymin=$ymin; wd=$wd; ht=$ht;"
		fi

		
		# compute longest edge length from intersection POINTS
		maxlen=0
		for ((i=0; i<4; i++)); do
			j=`convert xc: -format "%[fx:mod($i+1,4)]" info:`
			xa=${xsortArr[$i]}
			ya=${ysortArr[$i]}
			xb=${xsortArr[$j]}
			yb=${ysortArr[$j]}			
			dist=`convert xc: -format "%[fx:round(hypot($xa-$xb,$ya-$yb))]" info:`
			distArr[$i]=$dist
			[ $dist -gt $maxlen ] && maxlen=$dist
		done
		if $debug; then
			echo "maxlen=$maxlen"
		fi

		# get aspect ratio
		if [ "$aspect" = "points" ]; then
			compute_aspect_ratio
			aspect=$aspectratio
			[ "$info" = "yes" -o "$debug" = "true" ] && echo "aspect=$aspect;"
		elif [ "$aspect" = "edges" ]; then
			wa=`convert xc: -format "%[fx:(${distArr[1]}+${distArr[3]})/2]" info:`
			ha=`convert xc: -format "%[fx:(${distArr[0]}+${distArr[2]})/2]" info:`
			aspect=`convert xc: -format "%[fx:$wa/$ha]" info:`
		else
			test_numeric=`expr "$aspect" : '\([.0-9]*\)'`
			[ $test_numeric -eq 1 ] && errMsg "--- ASPECT MUST BE A NON-NEGATIVE FLOATING POINT VALUE ---"
		fi
		[ "$info" = "yes"  -o "$debug" = "true" ] && echo "aspect=$aspect;"


		# compute output size from aspect ratio, and width or height
		if [ "$height" != "" -a "$width" != "" ]; then
			errMsg "--- BOTH WIDTH AND HEIGHT CANNOT BE SPECIFIED AT THE SAME TIME ---"
		elif [ "$height" != "" ]; then
			oh=$height
			ow=`convert xc: -format "%[fx:floor($aspect*$oh)]" info:`
		elif [ "$width" != "" ]; then
			ow=$width
			oh=`convert xc: -format "%[fx:floor($ow/$aspect)]" info:`
		elif [ "$dimension" = "el" ]; then
			if [ `echo "$aspect>=1" | bc` -eq 1 ]; then
				ow=$maxlen
				oh=`convert xc: -format "%[fx:floor($ow/$aspect)]" info:`
			else
				oh=$maxlen
				ow=`convert xc: -format "%[fx:floor($aspect*$oh)]" info:`
			fi
		elif [ "$dimension" = "bh" ]; then
			oh=$ht
			ow=`convert xc: -format "%[fx:floor($aspect*$oh)]" info:`
		elif [ "$dimension" = "bw" ]; then
			ow=$wd
			oh=`convert xc: -format "%[fx:floor($ow/$aspect)]" info:`
		elif [ "$dimension" = "h" ]; then
			oh=$hh
			ow=`convert xc: -format "%[fx:floor($aspect*$oh)]" info:`
		elif [ "$dimension" = "w" ]; then
			ow=$ww
			oh=`convert xc: -format "%[fx:floor($ow/$aspect)]" info:`
		fi

		# Get 4 output coords (ccw from top left)
		opt0="0,0"
		opt1="0,$oh"
		opt2="$ow,$oh"
		opt3="$ow,0"
		
		cpts="${ptArr[0]} $opt0  ${ptArr[1]} $opt1  ${ptArr[2]} $opt2  ${ptArr[3]} $opt3"
		[ "$info" = "yes" -o "$debug" = "true" ] && echo "cpts=$cpts;"
		
		# enable alpha channel if mcolor is not fully opaque
		test=`convert xc:"$mcolor" -alpha extract -format "%[fx:u==1:1:0]" info:`
		if [ $test -eq 0 ]; then
			aproc="-alpha on"
		else
			aproc=""
		fi
		
		convert $tmpI1 $aproc -background "$mcolor" -virtual-pixel background \
			-define distort:viewport=${ow}x${oh}+0+0 +distort perspective "$cpts" +repage \
			$rotating "$outfile"

	fi

fi


if [ "$show" = "view" ]; then
	convert ${inname}_deskew.png show:
	convert ${inname}_canny.gif show:
	convert ${inname}_hough.png show:
	convert ${inname}_hough_longest4.png show:
	if [ "$procedure" = "deskew" -o "$procedure" = "unrotate" ]; then
		convert ${inname}_cropbox.png show:
	fi
	rm ${inname}_deskew.png ${inname}_canny.gif ${inname}_hough.png ${inname}_hough_longest4.png ${inname}_cropbox.png
fi

	
exit 0
