at main 660 lines 26 kB view raw
1#!/bin/bash 2# 3# Developed by Fred Weinhaus 12/30/2015 .......... revised 2/18/20201 4# 5# ------------------------------------------------------------------------------ 6# 7# Licensing: 8# 9# Copyright © Fred Weinhaus 10# 11# My scripts are available free of charge for non-commercial use, ONLY. 12# 13# For use of my scripts in commercial (for-profit) environments or 14# non-free applications, please contact me (Fred Weinhaus) for 15# licensing arrangements. My email address is fmw at alink dot net. 16# 17# If you: 1) redistribute, 2) incorporate any of these scripts into other 18# free applications or 3) reprogram them in another scripting language, 19# then you must contact me for permission, especially if the result might 20# be used in a commercial or for-profit environment. 21# 22# My scripts are also subject, in a subordinate manner, to the ImageMagick 23# license, which can be found at: http://www.imagemagick.org/script/license.php 24# 25# ------------------------------------------------------------------------------ 26# 27#### 28# 29# USAGE: multicrop2 [-c coords] [-b bcolor] [-f fuzzval] [-d discard] 30# [-u unrotate] [-i innertrim] [-e extend] [-m mask] [-t threshold] 31# [-r resize] [-D density] [-S sortval] [-s showstats] [-v vc] infile outfile 32# USAGE: multicrop [-h or -help] 33# 34# OPTIONS: 35# 36# -c coords pixel coordinate to extract background color; 37# may be expressed as gravity value (NorthWest, etc) 38# or as "x,y" value; default is NorthWest=(0,0) 39# -b bcolor background color to use instead of option -c; 40# any valid IM color; default is to use option -c 41# -f fuzzval fuzz value for separating background color; expressed 42# as (integer) percent 0 to 100; default=10 43# -d discard discard any region that has an area smaller than 44# this size; integer>0; default is to keep all 45# -u unrotate unrotate method; choices are 1 for -deskew, 2 for 46# unrotate script and 3 for no unrotate; default=1 47# -i innertrim trims inside the cropped area to an orthogonal rectangle; 48# yes or no; default=no 49# -e extend extend crop on each side in pixels; integer; default=0 50# -m mask mask presentation method; choices are view, 51# save (to file) or output mask only; default 52# is none of the above, just output the images 53# -t threshold threshold on number of objects; aborts if more than 54# threshold number of objects are detected; integer>0; 55# default is no abort and keep all objects. 56# -r resize resize percent to scale the image down; float>0; 57# default is no resizing. 58# -D density density to use when reading a single page of a PDF; 59# integer>0; default is no assigned density 60# -S sortval sort regions by upper left bounding box x,y coordinates 61# rounded to the specified positive integer increment; 62# default is no sorting 63# -s showstats show connected components stats; yes or no; default=no 64# -v keep virtual canvas; default is not to keep virtual canvas; 65# only valid for -u=3 (no unrotate) and for output format that 66# supports virtual canvas such as PNG or TIFF. 67# 68### 69# 70# NAME: MULTICROP2 71# 72# PURPOSE: To crop and unrotate multiple images from a scanned image. 73# 74# DESCRIPTION: MULTICROP2 crops and unrotates multiple images from a scanned image. 75# The images must be well separated so that background color shows between them. 76# The process uses a floodfill technique based upon a seed coordinate and a fuzz 77# value to separate the individual images from the background of the scan. 78# The correct choice of fuzz factor is very important. If too small, the images 79# will not be separate. If too large, parts of the outer area of the image 80# containing similar colors will be lost and the image may be separated into 81# multiple parts. There are two unrotate methods. The first uses the IM deskew 82# function, but is limited to 5 degrees of rotate or less. The second uses my 83# unrotate script. It allows much larger rotations, but will be slower. If 84# using the second method, my unrotate script must be downloaded and installed. 85# 86# IMPORTANT: The images in the scanned file must be well separated in x and y 87# so that their bounding boxes do not overlap. This is especially important 88# if the images have a significant rotation. 89# 90# The output images will be named from the specified outfile and -000, -001, 91# -002 etc, will be appended before the .suffix. 92# 93# Arguments: 94# 95# -c coords ... COORDS is any location within the background (non-image) area 96# for the algorithm to find the background color. It may be specified in terms 97# of gravity parameters (NorthWest, North, NorthEast, East, SouthEast, South, 98# SouthWest or West) or as a pixel coordinate "x,y". The default is the 99# upper left corner = NorthWest = "0,0". 100# 101# -b bcolor ... BCOLOR is the background color to use for flood fill instead 102# of extracting this color from the image. This is useful when an image has 103# no borders so that the sub-images are hard against the edges. The bcolor 104# will be used to put a one pixel border around the image and coords will be 105# set to 0,0. Any valid IM color is allowed. The default is to use option -c. 106# 107# -f fuzzval ... FUZZVAL is the fuzz amount specified as an integer percent 108# value between 0 to 100 (without the % sign). The correct choice of fuzz 109# factor is very important. If too small, the images will not be separate. 110# If too larger, parts of the outer area of the image containing similar 111# colors will be lost and the image may be separated into multiple parts. 112# Typical values are probably between 5 and 20 percent. The default=10. 113# (0 is uniform color) 114# 115# -d discard ... DISCARD any region that has an area smaller than the 116# specified discard size. Values are integer>0. The default is to keep all 117# regions. 118# 119# -u unrotate ... UNROTATE is the unrotation method. Choices are: 1, 2 or 3. 120# The default is unrotate=1, which is fast and uses the IM -deskew function, 121# but is limited to images that are rotated no more than 5 degrees in the scan 122# and generally a light background color. Option unrotate=2 uses my unrotate 123# script. It can handle larger rotations, but is slower. If using the latter 124# method, my unrotate script must be downloaded and also installed so that it 125# is available for this script to use. Option unrotate=3 makes no attempt to 126# unrotate the images. 127# 128# -i innertrim ... INNERTRIM trims inside the cropped area to an orthogonal 129# rectangle. Requires my script, autotrim. The choices are: yes or no. 130# The default=no. 131# 132# -e extend ... EXTEND crop on each side for the output images in pixels. 133# The extended region will come from the background of the image. Values are integers. 134# Positive makes the results larger. Negative makes the results smaller. Positive 135# values are only allowed for unrotate=3 (no unrotation) and innertrim=no. The default=0. 136# 137# -m mask ... MASK provides several options for reviewing the initial mask that 138# is generated by the fuzz value. The choices are: view (display to X11 window), 139# save (to disk) along with the images, or output (without processing the images). 140# The default is to simply process the images without showing or saving the mask. 141# If using the view mode, then processing will stop until the image is closed. 142# But this allows you to then kill the script if the mask is not appropriate. 143# A good approach is to use the output mode repeatedly with various fuzzvals 144# until a reasonable mask is created. Note that the mask must separate the 145# images, but the background can "eat" a little into the images so long as no 146# full edge is lost or the images is split into multiple parts. 147# 148# -t threshold ... THRESHOLD on the number of objects. The script aborts, if 149# more than the threshold number of objects are detected. Value must be 150# integers greater than 0. The default is no abort and keep all objects. 151# To avoid an abort, use the -d discard option. 152# 153# -r resize ... RESIZE amount in percent to scale the image down. Values are floats>0. 154# The default is no resizing. This is useful to improve speed and floodfilling 155# when you have a large image, especially if the background is grainy. Note: do not 156# include the % symbol. 157# 158# -D density ... DENSITY to use when reading a single page of a PDF. Multipage pdf 159# files are not permitted. Values are integers>0. The default is no assigned density. 160# 161# -S sortval ... SORT regions by their upper left bounding box x,y coordinates 162# rounded to the specified positive integer increment. The default is 163# no sorting. 164# 165# -s showstats ... SHOWSTATS shows the connected components statistics. 166# Choices are: yes (y) or no (n). The default=no. 167# 168# -v ... keep VIRTUAL CANVAS. The default is not to keep virtual canvas. This option 169# is only valid for -u=3 (no unrotate) and for output format that supports virtual 170# canvas such as PNG or TIFF. 171# 172# REQUIREMENTS: IM 6.8.9.10 due to the use of -connected-components. 173# If using unrotate method 2, then my script, unrotate, is required. 174# If using innertrim, then my script, autotrim is required. 175# 176# CAVEAT: No guarantee that this script will work on all platforms, 177# nor that trapping of inconsistent parameters is complete and 178# foolproof. Use At Your Own Risk. 179# 180###### 181# 182 183# set default values 184coords="" # initial coord for finding background color 185bcolor="" # initial background color 186fuzzval=10 # fuzz amount in percent for making background transparent 187discard="" # discard small regions 188extend=0 # extend the output crop on all sides 189mask="" # view, save, output 190threshold="" # threshold on number of objects; if larger, then abort 191unrotate=1 # 1=deskew 2=unrotate 192innertrim="no" # trim inside cropped area to orthogonal rectangle 193resize="" # resize percent 194density="" # density to use for input PDF 195sortval="" 196showstats="no" # show CCL stats 197vc="no" # keep virtual canvas 198debug="false" 199 200# set directory for temporary files 201dir="." # suggestions are dir="." or dir="/tmp" 202 203# set up functions to report Usage and Usage with Description 204PROGNAME=`type $0 | awk '{print $3}'` # search for executable on path 205PROGDIR=`dirname $PROGNAME` # extract directory of program 206PROGNAME=`basename $PROGNAME` # base name of program 207usage1() 208 { 209 echo >&2 "" 210 echo >&2 "$PROGNAME:" "$@" 211 sed >&2 -e '1,/^####/d; /^###/g; /^#/!q; s/^#//; s/^ //; 4,$p' "$PROGDIR/$PROGNAME" 212 } 213usage2() 214 { 215 echo >&2 "" 216 echo >&2 "$PROGNAME:" "$@" 217 sed >&2 -e '1,/^####/d; /^######/g; /^#/!q; s/^#*//; s/^ //; 4,$p' "$PROGDIR/$PROGNAME" 218 } 219 220# function to report error messages 221errMsg() 222 { 223 echo "" 224 echo $1 225 echo "" 226 usage1 227 exit 1 228 } 229 230# function to test for minus at start of value of second part of option 1 or 2 231checkMinus() 232 { 233 test=`echo "$1" | grep -c '^-.*$'` # returns 1 if match; 0 otherwise 234 [ $test -eq 1 ] && errMsg "$errorMsg" 235 } 236 237# test for correct number of arguments and get values 238if [ $# -eq 0 ] 239 then 240 # help information 241 echo "" 242 usage2 243 exit 0 244elif [ $# -gt 29 ] 245 then 246 errMsg "--- TOO MANY ARGUMENTS WERE PROVIDED ---" 247else 248 while [ $# -gt 0 ] 249 do 250 # get parameters 251 case "$1" in 252 -h|-help) # help information 253 echo "" 254 usage2 255 ;; 256 -f) # fuzzval 257 shift # to get the next parameter 258 # test if parameter starts with minus sign 259 errorMsg="--- INVALID FUZZVAL SPECIFICATION ---" 260 checkMinus "$1" 261 fuzzval=`expr "$1" : '\([0-9]*\)'` 262 [ "$fuzzval" = "" ] && errMsg "--- FUZZVAL=$fuzzval MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---" 263 fuzzvaltestA=`echo "$fuzzval < 0" | bc` 264 fuzzvaltestB=`echo "$fuzzval > 100" | bc` 265 [ $fuzzvaltestA -eq 1 -a $fuzzvaltestB -eq 1 ] && errMsg "--- FUZZVAL=$fuzzval MUST BE A NON-NEGATIVE INTEGER VALUE BETWEEN 0 AND 100 ---" 266 ;; 267 -c) # coords 268 shift # to get the next parameter 269 # test if parameter starts with minus sign 270 errorMsg="--- INVALID COORDS SPECIFICATION ---" 271 checkMinus "$1" 272 coords=$1 273 # further testing done later 274 ;; 275 -b) # bcolor 276 shift # to get the next parameter 277 # test if parameter starts with minus sign 278 errorMsg="--- INVALID BCOLOR SPECIFICATION ---" 279 checkMinus "$1" 280 bcolor=$1 281 ;; 282 -d) # discard 283 shift # to get the next parameter 284 # test if parameter starts with minus sign 285 errorMsg="--- INVALID DISCARD SPECIFICATION ---" 286 checkMinus "$1" 287 discard=`expr "$1" : '\([0-9]*\)'` 288 [ "$discard" = "" ] && errMsg "--- DISCARD=$discard MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---" 289 testA=`echo "$discard < 1" | bc` 290 [ $testA -eq 1 ] && errMsg "--- DISCARD=$discard MUST BE A NON-NEGATIVE INTEGER VALUE GREATER THAN 0 ---" 291 ;; 292 -e) # extend 293 shift # to get the next parameter 294 # test if parameter starts with minus sign 295 errorMsg="--- INVALID EXTEND SPECIFICATION ---" 296 #checkMinus "$1" 297 extend=`expr "$1" : '\([-0-9]*\)'` 298 [ "$extend" = "" ] && errMsg "--- EXTEND=$extend MUST BE AN INTEGER VALUE (with no sign) ---" 299 ;; 300 -u) # unrotate 301 shift # to get the next parameter 302 # test if parameter starts with minus sign 303 errorMsg="--- INVALID UNROTATE SPECIFICATION ---" 304 checkMinus "$1" 305 unrotate=`expr "$1" : '\([0-9]\)'` 306 [ $unrotate -lt 1 -a $unrotate -gt 3 ] && errMsg "--- UNROTATE=$unrotate MUST BE EITHER 1, 2, 3 OR 4 ---" 307 ;; 308 -i) # get innertrim 309 shift # to get the next parameter 310 # test if parameter starts with minus sign 311 errorMsg="--- INVALID INNERTRIM SPECIFICATION ---" 312 checkMinus "$1" 313 innertrim="$1" 314 innertrim=`echo "$innertrim" | tr "[:upper:]" "[:lower:]"` 315 case "$innertrim" in 316 yes|y) innertrim="yes" ;; 317 no|n) innertrim="no" ;; 318 *) errMsg "--- INNERTRIM=$innertrim IS AN INVALID VALUE ---" 319 esac 320 ;; 321 -m) # mask 322 shift # to get the next parameter 323 # test if parameter starts with minus sign 324 errorMsg="--- INVALID MASK SPECIFICATION ---" 325 checkMinus "$1" 326 mask=`echo "$1" | tr "[:upper:]" "[:lower:]"` 327 [ "$mask" != "view" -a "$mask" != "save" -a "$mask" != "output" ] && errMsg "--- MASK=$mask MUST BE EITHER VIEW, SAVE OR OUTPUT ---" 328 ;; 329 -t) # threshold 330 shift # to get the next parameter 331 # test if parameter starts with minus sign 332 errorMsg="--- INVALID THRESHOLD SPECIFICATION ---" 333 checkMinus "$1" 334 threshold=`expr "$1" : '\([0-9]*\)'` 335 [ "$threshold" = "" ] && errMsg "--- THRESHOLD=$threshold MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---" 336 testA=`echo "$threshold < 1" | bc` 337 [ $testA -eq 1 ] && errMsg "--- THRESHOLD=$threshold MUST BE A NON-NEGATIVE INTEGER VALUE GREATER THAN 0 ---" 338 ;; 339 -r) # resize 340 shift # to get the next parameter 341 # test if parameter starts with minus sign 342 errorMsg="--- INVALID RESIZE SPECIFICATION ---" 343 checkMinus "$1" 344 resize=`expr "$1" : '\([.0-9]*\)'` 345 [ "$resize" = "" ] && errMsg "--- RESIZE=$resize MUST BE A NON-NEGATIVE FLOAT VALUE (with no sign) ---" 346 testA=`echo "$resize == 0" | bc` 347 [ $testA -eq 1 ] && errMsg "--- RESIZE=$resize MUST BE A NON-NEGATIVE FLOAT VALUE GREATER THAN 0 ---" 348 ;; 349 -D) # density 350 shift # to get the next parameter 351 # test if parameter starts with minus sign 352 errorMsg="--- INVALID DENSITY SPECIFICATION ---" 353 checkMinus "$1" 354 density=`expr "$1" : '\([0-9]*\)'` 355 [ "$density" = "" ] && errMsg "--- DENSITY=$density MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---" 356 testA=`echo "$density == 0" | bc` 357 [ $testA -eq 1 ] && errMsg "--- DENSITY=$density MUST BE A NON-NEGATIVE INTEGER VALUE GREATER THAN 0 ---" 358 ;; 359 -S) # sortval 360 shift # to get the next parameter 361 # test if parameter starts with minus sign 362 errorMsg="--- INVALID SORTVAL SPECIFICATION ---" 363 checkMinus "$1" 364 sortval=`expr "$1" : '\([0-9]*\)'` 365 testA=`echo "$sortval == 0" | bc` 366 [ $testA -eq 1 ] && errMsg "--- SORTVAL=$sortval MUST BE AN INTEGER VALUE GREATER THAN 0 ---" 367 ;; 368 -s) # showstats 369 shift # to get the next parameter 370 # test if parameter starts with minus sign 371 errorMsg="--- INVALID SHOWSTATS SPECIFICATION ---" 372 checkMinus "$1" 373 showstats=`echo "$1" | tr "[:upper:]" "[:lower:]"` 374 [ "$showstats" != "yes" -a "$showstats" != "no" ] && errMsg "--- SHOWSTATS=$showstats MUST BE EITHER YES OR NO ---" 375 ;; 376 -v) # vc 377 vc="yes" 378 ;; 379 -) # STDIN and end of arguments 380 break 381 ;; 382 -*) # any other - argument 383 errMsg "--- UNKNOWN OPTION ---" 384 ;; 385 *) # end of arguments 386 break 387 ;; 388 esac 389 shift # next option 390 done 391 # get infile and outfile 392 infile="$1" 393 outfile="$2" 394fi 395 396# test if both bcolor and coords specified at the same time 397if [ "$bcolor" != "" -a "$coords" != "" ]; then 398 errMsg "--- BACKGROUND COLOR AND COODINATES CAN NOT BE USED TOGETHER ---" 399elif [ "$bcolor" = "" -a "$coords" = "" ]; then 400 coords="0,0" 401fi 402 403# test that infile provided 404[ "$infile" = "" ] && errMsg "NO INPUT FILE SPECIFIED" 405 406# test that outfile provided 407[ "$outfile" = "" ] && errMsg "NO OUTPUT FILE SPECIFIED" 408 409# test if input is single layer/page/frame 410count=`convert -ping "$infile" -format "%m\n" info: | wc -l` 411[ $count -gt 1 ] && errMsg "--- MULTIPAGE/MULTIFRAME/MULTILAYER IMAGES ARE NOT ALLOWED ---" 412 413if [ "$density" != "" ]; then 414 dproc="-density $density" 415else 416 dproc="" 417fi 418 419# set up temp file 420tmpA1="$dir/multicrop2_1_$$.mpc" 421tmpB1="$dir/multicrop2_1_$$.cache" 422tmpA2="$dir/multicrop2_2_$$.mpc" 423tmpB2="$dir/multicrop2_2_$$.cache" 424tmpA3="$dir/multicrop2_3_$$.miff" 425tmpA4="$dir/multicrop2_4_$$.mpc" 426tmpB4="$dir/multicrop2_4_$$.cache" 427 428trap "rm -f $tmpA1 $tmpB1 $tmpA2 $tmpB2 $tmpA3 $tmpB4 $tmpA4;" 0 429trap "rm -f $tmpA1 $tmpB1 $tmpA2 $tmpB2 $tmpA3 $tmpB4 $tmpA4; exit 1" 1 2 3 15 430#trap "rm -f $tmpA1 $tmpB1 $tmpA2 $tmpB2 $tmpA3; exit 1" ERR 431 432# read the input image into the temp files and test validity. 433if [ "$resize" != "" ]; then 434 convert -quiet $dproc "$infile" +repage "$tmpA4" || 435 errMsg "--- FILE $infile1 DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---" 436 convert "$tmpA4" -scale $resize% "$tmpA1" 437else 438 convert -quiet $dproc "$infile" +repage "$tmpA1" || 439 errMsg "--- FILE $infile1 DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---" 440fi 441 442 443# get im_version 444im_version=`convert -list configure | \ 445 sed '/^LIB_VERSION_NUMBER */!d; s//,/; s/,/,0/g; s/,0*\([0-9][0-9]\)/\1/g' | head -n 1` 446 447# get output filename and suffix 448outnameArr=(`echo "$outfile" | sed -n 's/^\(.*\)[.]\([^.]*\)$/\1 \2/p'`) 449outname="${outnameArr[0]}" 450suffix="${outnameArr[1]}" 451#echo "outname=$outname" 452#echo "suffix=$suffix" 453 454if [ "$im_version" -ge "07000000" ]; then 455 identifying="magick identify" 456else 457 identifying="identify" 458fi 459 460# get image width and height 461width=`$identifying -ping -format "%w" $tmpA1` 462height=`$identifying -ping -format "%h" $tmpA1` 463 464# test for extend 465test=`convert xc: -format "%[fx:$extend>0?1:0]" info:` 466[ $test -eq 1 -a $unrotate -ne 3 ] && errMsg "--- SIGN FOR EXTEND=$extend MUST BE NEGATIVE ---" 467[ $test -eq 1 -a $unrotate -eq 3 -a "$innertrim" = "yes" ] && errMsg "--- SIGN FOR EXTEND=$extend MUST BE NEGATIVE ---" 468 469# test if coords provided as x,y 470# coords="" if test fails and have other characters such as northwest 471coords1=`expr "$coords" : '\([0-9]*,[0-9]*\)'` 472 473# get color at user specified location 474if [ "$bcolor" != "" ]; then 475 coords="0,0" 476elif [ "$coords1" != "" -a "$resize" != "" ]; then 477 x=`echo "$coords1" | cut -d, -f1` 478 y=`echo "$coords1" | cut -d, -f2` 479 x=`convert xc: -format "%[fx:round($x*$resize/100)]" info:` 480 y=`convert xc: -format "%[fx:round($y*$resize/100)]" info:` 481 coords="$x,$y" 482 bcolor=`convert $tmpA1 -format "%[pixel:u.p{$coords}]" info:` 483elif [ "$coords1" != "" -a "$resize" = "" ]; then 484 x=`echo "$coords1" | cut -d, -f1` 485 y=`echo "$coords1" | cut -d, -f2` 486 # account for pad of 1 487 x=$((x+1)) 488 y=$((y+1)) 489 coords="$x,$y" 490 bcolor=`convert $tmpA1 -format "%[pixel:u.p{$coords}]" info:` 491elif [ "$coords1" = "" ]; then 492 widthm1=`convert xc: -format "%[fx:$width-1]" info:` 493 heightm1=`convert xc: -format "%[fx:$height-1]" info:` 494 midwidth=`convert xc: -format "%[fx:round(($width-1))/2]" info:` 495 midheight=`convert xc: -format "%[fx:round(($height-1))/2]" info:` 496 coords=`echo "$coords" | tr "[:upper:]" "[:lower:]"` 497 case "$coords" in 498 ''|nw|northwest) coords="0,0" ;; 499 n|north) coords="$midwidth,0" ;; 500 ne|northeast) coords="$widthm1,0" ;; 501 e|east) coords="$widthm1,$midheight" ;; 502 se|southeast) coords="$widthm1,$heightm1" ;; 503 s|south) coords="$midwidth,$heightm1" ;; 504 sw|southwest) coords="0,$heightm1" ;; 505 w|west) coords="0,$midheight" ;; 506 *) errMsg "--- INVALID COORDS ---" ;; 507 esac 508 bcolor=`convert $tmpA1 -format "%[pixel:u.p{$coords}]" info:` 509fi 510#echo "bcolor=$bcolor" 511 512# set up floodfill 513if [ "$im_version" -ge "07000000" ]; then 514 matte_alpha="alpha" 515else 516 matte_alpha="matte" 517fi 518 519# add a border, and flood fill from all edges inward 520convert $tmpA1 -fuzz ${fuzzval}% -fill none \ 521 -bordercolor $bcolor -border 1x1 \ 522 -draw "$matte_alpha $coords floodfill" \ 523 -shave 1x1 -fill white +opaque none \ 524 -background black -alpha background -alpha off -type bilevel \ 525 $tmpA2 526 527if [ "$mask" = "view" ]; then 528 display $tmpA2 529elif [ "$mask" = "save" ]; then 530 convert $tmpA2 ${outname}_mask.gif 531elif [ "$mask" = "output" ]; then 532 convert $tmpA2 ${outname}_mask.gif 533 exit 0 534fi 535 536# set up for unrotate 1 or 3 537if [ $unrotate -eq 1 ]; then 538 derotate="-background $bcolor -deskew 40%" 539elif [ $unrotate -eq 3 ]; then 540 derotate="" 541fi 542 543# set up discard 544if [ "$discard" != "" ]; then 545 discarding="-define connected-components:area-threshold=$discard" 546else 547 discarding="" 548fi 549 550# process image using connected components labeling 551echo "" 552data=`convert $tmpA2 -precision 15 \ 553 -define connected-components:verbose=true \ 554 $discarding -connected-components 4 null:` 555[ "$showstats" = "yes" ] && echo "$data" 556 557wwArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $2}'`) 558hhArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $3}'`) 559xoArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $4}'`) 560yoArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $5}'`) 561colorArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,gray\(\)\n" " " | awk '{print $8}'`) 562num=${#wwArr[*]} 563#echo $num 564 565# do sorting if specified 566if [ "$sortval" != "" ]; then 567 # build dataArr and sort it 568 # note new line before last quote so have list for sorting 569 # add rounded points for sorting 570 nearest=$sortval 571 for((i=0; i<num; i++)); do 572 xx=${xoArr[$i]} 573 yy=${yoArr[$i]} 574 xr=`convert xc: -format "%[fx:$nearest*round($xx/$nearest)]" info:` 575 yr=`convert xc: -format "%[fx:$nearest*round($yy/$nearest)]" info:` 576 dataArr[$i]="${wwArr[$i]} ${hhArr[$i]} ${xoArr[$i]} ${yoArr[$i]} ${colorArr[$i]} $xr $yr 577" 578 #echo ${dataArr[$i]} 579 done 580 OLDIFS=$IFS 581 IFS=$'\n' 582 sortArr=(`echo "${dataArr[*]}" | sort -n -k7,7 -k6,6`) 583 IFS=$OLDIFS 584 for((i=0; i<num; i++)); do 585 #echo "${sortArr[$i]}" 586 wwArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f1` 587 hhArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f2` 588 xoArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f3` 589 yoArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f4` 590 colorArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f5` 591 done 592fi 593 594# abort if too many objects 595# subtract 1 for background 596numm1=$((num-1)) 597if [ "$threshold" != "" ]; then 598 [ $numm1 -gt $threshold ] && errMsg "--- TOO MANY OBJECTS DETECTED ---" 599fi 600 601if [ "$vc" = "yes" ]; then 602 repaging="" 603else 604 repaging="+repage" 605fi 606#echo "repaging=$repaging;" 607 608echo "" 609k=0 610for ((i=0; i<num; i++)); do 611 color="${colorArr[$i]}" 612 if [ "$color" != "gray(0)" ]; then 613 echo "Processing Image $k" 614 kk=`printf "%03d" "$k"` 615 offx=${xoArr[$i]} 616 offy=${yoArr[$i]} 617 wd=${wwArr[$i]} 618 ht=${hhArr[$i]} 619 if [ "$resize" != "" ]; then 620 wd=`convert xc: -format "%[fx:round($wd*100/$resize)+2*$extend]" info:` 621 ht=`convert xc: -format "%[fx:round($ht*100/$resize)+2*$extend]" info:` 622 offx=`convert xc: -format "%[fx:round($offx*100/$resize)-$extend]" info:` 623 offy=`convert xc: -format "%[fx:round($offy*100/$resize)-$extend]" info:` 624 img=$tmpA4 625 else 626 wd=$((wd+2*extend)) 627 ht=$((ht+2*extend)) 628 offx=$((offx-extend)) 629 offy=$((offy-extend)) 630 img=$tmpA1 631 fi 632 echo "Initial Crop Box: ${wd}x${ht}+${offx}+${offy}" 633 echo "" 634 if [ $unrotate -eq 3 ]; then 635 convert $img -crop ${wd}x${ht}+${offx}+${offy} $repaging $tmpA3 636 elif [ $unrotate -eq 1 ]; then 637 convert $img -crop ${wd}x${ht}+${offx}+${offy} +repage $derotate \ 638 -bordercolor "$bcolor" -border 2 -fuzz ${fuzzval}% -trim +repage $tmpA3 639 elif [ $unrotate -eq 2 ]; then 640 convert $img -crop ${wd}x${ht}+${offx}+${offy} +repage \ 641 -fuzz ${fuzzval}% -trim miff:- | \ 642 unrotate -C "$bcolor" -f ${fuzzval}% - $tmpA3 643 fi 644 if [ "$innertrim" = "yes" ]; then 645 mextend=-$extend 646 autotrim -m inner -f $fuzzval -C "$bcolor" -l $mextend -t $mextend \ 647 -r $extend -b $extend $tmpA3 ${outname}-${kk}.${suffix} 648 echo "" 649 else 650 convert $tmpA3 ${outname}-${kk}.${suffix} 651 fi 652 k=$((k+1)) 653 fi 654done 655echo "" 656 657exit 0 658 659 660