#!/bin/bash
#
# Developed by Fred Weinhaus 6/25/2014 .......... revised 2/14/2022
#
# ------------------------------------------------------------------------------
# 
# 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: kmeans [-n numcolors] [-s seedcolors] [-m maxiters] [-c convergence] [-a area] 
# [-t type] [-C colorspace] [-b bgcolor] [-v view] [-A adjoin] [-k compression]
# infile outfile
# USAGE: kmeans [-h or -help]
#
# OPTIONS:
#
# -n     numcolors       number of colors to use as seeds; integer>1; default=5
# -s     seedcolors      list of seed colors rather than selecting a number of 
#                        colors; space separate list of opaque color; default  
#                        is to use the number of colors
# -m     maxiters        maximum number of iterations before stopping; 
#                        integer>0; default=40
# -c     convergence     minimum rmse (times 100) between previous and current 
#                        set of colors to stop iterating; default=0.05
# -a     area            largest pixel area of a cluster to be merged into 
#                        its background; integer>=0; default=0 (no merging)
# -t     type            type of output; choices are flattened (f) or 
#                        layered (l); default=flattened
# -C     colorspace      colorspace in which to do processing; default=sRGB
# -b     bgcolor         color to put under any transparency; any valid opaque
#                        color is allowed; default is no change of color
# -v     view            hexcolors (only), swatches (and hex colors), 
#                        progress (and hex colors), all (progress, hexcolors 
#                        swatches) and dominant (dominant color).
# -A     adjoin          adjoin layered output images into a single multi-page 
#                        image; choices are: yes (y) or no (n); default=yes
# -k     compression     compression type if saved to tif; choices are: none (n), 
#                        lzw (l), or zip (z); default=zip
#
###
#
# NAME: KMEANS 
# 
# PURPOSE: To apply k-means color reduction to an image.
# 
# DESCRIPTION: KMEANS applies k-means color reduction to an image. This is a 
# colorspace clustering or segmentation technique. The user must specify either 
# a number of desired final colors or a set of initial seed colors. If a list 
# of seed colors is not provided, then seed colors will be estimated using IM 
# -colors (color quantization). The algorithm uses the seed colors to group 
# (cluster) each pixel in the image according to the smallest rmse value to  
# each seed color. Then it computes the new mean colors from the clusters. 
# This process iterates until either the convergence value is reached or the 
# maximum number of iterations is reached. The script is limited to fully 
# opaque images for type=layered. If type=flattened, then the input may have 
# and alpha channel that will be remove for processing and added back at the 
# end. Optionally, connected components labeling may be use to remove small 
# isolated clusters for IM versions 6.8.9-10 or later. The final list of 
# colors will be sorted by histogram count so that the first color in the 
# list will be the dominant color in the image.
# 
# OPTIONS: 
#
# -n numcolors ... NUMCOLORS is the number of colors to use as seeds. Values 
# are integer>1. The default=5.
# 
# -s seedcolors ... SEEDCOLORS is a space delimited list of opaque seed colors.  
# It is used rather than just selecting a given number of colors. Providing a  
# well selected list of colors can make the iteration process quicker. Any 
# valid set of opaque IM colors may be used. This includes rgb, hex or color 
# names. However, there must not be any spaces in the color, especially for rgb 
# color definitions. The default is to just use the desired number of colors.
# 
# -m maxiters ... MAXITERS is the maximum number of iterations before stopping. 
# Values are integer>0. The default=40
# 
# -c convergence ... CONVERGENCE is the minimum rmse (times 100) between the 
# previous and current set of colors to stop iterating. Values are floats>=0. 
# Larger convergence values will run faster and converge to slightly different
# colors. The default=0.05, but runs rather slow due to many iterations. 
# A value of 0.3 will run much faster with much fewer iterations, though the 
# colors will be slightly different and thus the clusters will be different.
# 
# -a area ... AREA is the largest pixel area of a cluster to be merged into 
# its surrounding or largest neighboring cluster (color). Any cluster of this 
# area or smaller will be merged. Value are integers>=0. The default=0 is no 
# merging.
# 
# -t type ... TYPE of output image. The choices are flattened (f) or 
# layered (l). The default=flattened. Note the format of the output must be 
# either GIF or TIF or TIFF to support the multi-page layered option, unless  
# -A adjoin is set to no. Suffixes may be all upper case or all lower case. 
# If other formats are used, then multiple output images will be created rather  
# than a layered image.
# 
# -C colorspace ... COLORSPACE in which to do processing; default=sRGB; other 
# colorspaces that do well are YCbCr and LAB.
# 
# -b bgcolor ... BGCOLOR is the backgrouond color to put under any transparency.
# Any valid opaque color is allowed. The default is no change of color.
# 
# -v view ... VIEW permits one to list to the terminal or display any of the
# following options: hexcolors, swatches (and hex colors), progress (and hex
# colors), all (progress, hexcolors swatches) and dominant (dominant color). 
# Hexcolors will list to the terminal for both  the initial seed and
# final cluster colors in hex notation. The final colors will be sorted by
# histogram count with the first color the dominant color in the resulting
# image. Swatches will display the initial and final cluster colors as images
# to the display. It will also list the hex colors to the terminal. Progress
# will list each iteration and rmse value to the terminal in addition to the
# list of initial and final hex colors. All will do all of the above. Dominant
# will list only the hexcolor value of the dominant color in the image. The
# default is none of the above. Note that hexcolors and swatches will be
# presented in the working colorspace and not converted to sRGB.
# 
# -A adjoin ... ADJOIN layered output images into a single multi-page image. 
# The choices are: yes (y) or no (n). The default=yes.
# 
# -k compression ... COMPRESSION type if saved to tif. The choices are: none (n), 
# lzw (l), or zip (z); default=zip
# 
# REQUIREMENTS: IM version 6.8.9-10 or higher to use option -a with connected 
# components labeling to remove small isolated clusters.
# 
# References:
# http://en.wikipedia.org/wiki/Kmeans
# 
# NOTE: the script may be slow due to its iterative nature. Also GIF files 
# cannot be made transparent in IM 6.9.1.7.
# 
# 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
numcolors="5"		# number of colors to use as seeds; corresponds to k in k-means
seedcolors=""		# use this list of colors for seeds rather than selecting a number of colors
maxiters=40			# maximum number of iterations; stops if reaches this limit
convergence=0.05	# minimum rmse between previous and current set of colors; if rmse at some iteration is smaller, then stop; usually stops at 0% before reaching this value or maxiters
area=0				# maximum area to be merged into its surrounding/neighboring cluster
type="flattened"    # type of output; flattened or layered
colorspace="sRGB"	# working colorspace
bgcolor=""			# background color to put under transparency
view=""				# hexcolors (only), swatches (and hex colors), progress (and hex colors), all
adjoin="yes"
compression="zip"

# set directory for temporary files
tmpdir="."    # suggestions are tmpdir="." or tmpdir="/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 22 ]
	then
	errMsg "--- TOO MANY ARGUMENTS WERE PROVIDED ---"
else
	while [ $# -gt 0 ]
		do
			# get parameter values
			case "$1" in
		  -h|-help)    # help information
					   echo ""
					   usage2
					   exit 0
					   ;;
				-n)    # get numcolors
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID NUMCOLORS SPECIFICATION ---"
					   checkMinus "$1"
					   numcolors=`expr "$1" : '\([0-9]*\)'`
					   [ "$numcolors" = "" ] && errMsg "--- NUMCOLORS=$numcolors MUST BE AN INTEGER ---"
		   			   testA=`echo "$numcolors < 2" | bc`
					   [ $testA -eq 1 ] && errMsg "--- NUMCOLORS=$numcolors MUST BE AN INTEGER GREATER THAN 1 ---"
					   ;;
				-s)    # get seedcolors
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID SEEDCOLORS SPECIFICATION ---"
					   checkMinus "$1"
					   seedcolors="$1"
					   ;;
				-m)    # get maxiters
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID MAXITERS SPECIFICATION ---"
					   checkMinus "$1"
					   maxiters=`expr "$1" : '\([0-9]*\)'`
					   [ "$maxiters" = "" ] && errMsg "--- MAXITERS=$maxiters MUST BE AN INTEGER ---"
		   			   testA=`echo "$maxiters < 1" | bc`
					   [ $testA -eq 1 ] && errMsg "--- MAXITERS=$maxiters MUST BE AN INTEGER GREATER THAN 1 ---"
					   ;;
				-c)    # get convergence
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID CONVERGENCE SPECIFICATION ---"
					   checkMinus "$1"
					   convergence=`expr "$1" : '\([.0-9]*\)'`
					   [ "$convergence" = "" ] && errMsg "--- CONVERGENCE=$convergence MUST BE A NON-NEGATIVE FLOAT ---"
					   ;;
				-a)    # get area
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID AREA SPECIFICATION ---"
					   checkMinus "$1"
					   area=`expr "$1" : '\([0-9]*\)'`
					   [ "$area" = "" ] && errMsg "--- AREA=$area MUST BE AN INTEGER ---"
					   ;;
				-t)    # get type
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign
					   errorMsg="--- INVALID TYPE SPECIFICATION ---"
					   checkMinus "$1"
					   type=`echo "$1" | tr "[:upper:]" "[:lower:]"`
					   case "$type" in
							flattened|f) type="flattened";;
							layered|l) type="layered";;
							*)  errMsg "--- TYPE=$type IS NOT A VALID VALUE ---" ;;
					   esac
					   ;;
				-C)    # get colorspace
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID COLORSPACE SPECIFICATION ---"
					   checkMinus "$1"
					   colorspace="$1"
					   ;;
				-b)    # get bgcolor
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID BGCOLOR SPECIFICATION ---"
					   checkMinus "$1"
					   bgcolor="$1"
					   ;;
				-v)    # get view
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign
					   errorMsg="--- INVALID VIEW SPECIFICATION ---"
					   checkMinus "$1"
					   view=`echo "$1" | tr "[:upper:]" "[:lower:]"`
					   case "$view" in
							hexcolors|hex|h) view="hexcolors";;
							swatches|s) view="swatches";;
							progress|p) view="progress";;
							all|a) view="all";;
							dominant|d) view="dominant";;
							*)  errMsg "--- VIEW=$view IS NOT A VALID VALUE ---" ;;
					   esac
					   ;;
				-A)    # get adjoin
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign
					   errorMsg="--- INVALID ADJOIN SPECIFICATION ---"
					   checkMinus "$1"
					   adjoin=`echo "$1" | tr "[:upper:]" "[:lower:]"`
					   case "$adjoin" in
							yes|y) adjoin="yes";;
							no|n) adjoin="no";;
							*)  errMsg "--- ADJOIN=$adjoin IS NOT A VALID VALUE ---" ;;
					   esac
					   ;;
				-k)    # get compression
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign
					   errorMsg="--- INVALID COMPRESSION SPECIFICATION ---"
					   checkMinus "$1"
					   compression=`echo "$1" | tr "[:upper:]" "[:lower:]"`
					   case "$compression" in
							none|n) compression="none";;
							lzw|l) compression="lzw";;
							zip|z) compression="zip";;
							*)  errMsg "--- COMPRESSION=$compression IS NOT A VALID 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, 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 ---"


dir="$tmpdir/KMEANS.$$"

mkdir "$dir" || errMsg "--- FAILED TO CREATE TEMPORARY FILE DIRECTORY ---"
trap "rm -rf $dir; exit 0" 0
trap "rm -rf $dir; exit 1" 1 2 3 15



# test if alpha channel
channels=`convert -quiet "$infile" -format "%[channels]" info:`
last_char=`echo ${channels:${#channels} - 1}`
#echo "channels=$channels; last_char=$last_char;"

# test if infile exists, is readable and is not zero size
if [ "$last_char" = "a" ]; then
	if [ "$bgcolor" != "" ]; then
		bgproc="-background $bgcolor -alpha background"
	else
		bgproc=""
	fi
	convert -quiet "$infile" +repage $bgproc \
		\( -clone 0 -alpha extract +write $dir/tmpA.miff +delete \) \
		-alpha off -colorspace $colorspace -set colorspace sRGB $dir/tmpI.miff ||
		echo  "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE  ---"
else
	convert -quiet "$infile" +repage -colorspace $colorspace -set colorspace sRGB $dir/tmpI.miff ||
		echo  "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE  ---"
fi


# get IM version
im_version=`convert -list configure | \
	sed '/^LIB_VERSION_NUMBER */!d; s//,/;  s/,/,0/g;  s/,0*\([0-9][0-9]\)/\1/g' | head -n 1`


if [ "$im_version" -ge "07000000" ]; then
	identifying="magick identify"
else
	identifying="identify"
fi

# get image dimensions
ww=`$identifying -ping -format "%w" $dir/tmpI.miff`
hh=`$identifying -ping -format "%h" $dir/tmpI.miff`
#echo "ww=$ww; hh=$hh;"


# get seed colors
if [ "$seedcolors" != "" ]; then
	# get array of colors
	colorArr=($seedcolors)
	#echo "colors=${colorArr[*]};"
	numcolors=${#colorArr[*]}
	#echo "numcolors=$numcolors;"
elif [ "$numcolors" != "" ]; then
	colorArr=(`convert $dir/tmpI.miff -alpha off \
		+dither -colors $numcolors -unique-colors txt:- |\
		tail -n +2 | grep -o "#[^ ]*"`)
	[ "$view" = "hexcolors" -o "$view" = "swatches" -o "$view" = "progress" -o "$view" = "all" ] && echo "seed colors = ${colorArr[*]}"
	numcolors=${#colorArr[*]}
	#echo "numcolors=$numcolors;"
	[ "$view" = "swatches" -o "$view" = "all" ] && convert $dir/tmpI.miff -colors $numcolors -unique-colors -scale 5000% show:
fi

# set up for flattening
if [ "$type" = "flattened" ]; then
	flattening="-background none -flatten"
else
	flattening=""
fi

# set up for adjoin
if [ "$adjoin" = "no" ]; then
	adjoining="+adjoin"
else
	adjoining=""
fi

# set up for tif compression
# get suffix
suffix="${outfile##*.}"
# change to lower case
suffix=`echo "$suffix" | tr '[:upper:]' '[:lower:]'`
echo "$suffix"
if [ "$suffix" = "tif" -o "$suffix" = "tiff" ]; then
	compressing="-compress $compression"
else
	compressing=""
fi
echo "$compressing"

# process kmeans code
# create white image
# note must add -colorspace gray for IM 7; 
# otherwise it will be doing -evaluate-sequence later between 3 channel white image and grayscale images,
# which will produce a cyan result.
convert -size ${ww}x${hh} xc:white -colorspace gray $dir/tmpW.miff

# loop over iterations
for ((k=0; k<maxiters; k++)); do

	# initialize to white (max) for rmse difference images
	convert $dir/tmpW.miff $dir/tmpD.miff

	# loop over colors and get min rmse at each pixel
	for (( i=0;i<numcolors; i++)); do

		# get rmse for color vs image
		convert $dir/tmpI.miff \( -size ${ww}x${hh} xc:"${colorArr[$i]}" \) \
		-compose difference -composite +duplicate -compose over -compose multiply -composite \
		-separate +channel -evaluate-sequence mean -evaluate pow 0.5 $dir/tmpCD$i.miff
	
		# get smallest rmse for all color rmse images
		convert $dir/tmpD.miff $dir/tmpCD$i.miff -evaluate-sequence min $dir/tmpD.miff 
	done

	# create mask for each color
	for (( i=0;i<numcolors; i++)); do
	
		# compare smallest rmse to each color rmse and threshold
		convert $dir/tmpD.miff $dir/tmpCD$i.miff -compose difference -composite -threshold 0 -negate $dir/tmpM$i.miff

		# get new mean colors for each regions
		newcolorArr[$i]=`convert $dir/tmpI.miff $dir/tmpM$i.miff -alpha off -compose copy_opacity -composite \
			-scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:`
	done

	# compare colors to get rmse difference
	diffsq=0
	for (( i=0;i<numcolors; i++)); do
		colordiff=`convert -size 1x1 xc:"${colorArr[$i]}" xc:"${newcolorArr[$i]}" \
			-format "%[fx:((u.r-v.r)^2+(u.g-v.g)^2+(u.b-v.b)^2)/3]\n" info: | head -n 1`
		diffsq=`convert xc: -format "%[fx:$diffsq + $colordiff]" info:`
	done
	rmse=`convert xc: -format "%[fx:100*sqrt($diffsq/$numcolors)]" info:`
	if [ "$view" = "progress" -o "$view" = "all" ]; then
		j=$((k+1))
		echo "iteration=$j 100*rmse=$rmse"
	fi
	
	test=`convert xc: -format "%[fx:$rmse<$convergence?1:0]" info:`
	[ $test -eq 1 ] && break

	# update color arrays
	for (( i=0;i<numcolors; i++)); do
		colorArr[$i]="${newcolorArr[$i]}"
	done
done


# colorize masks to show segmentation and make rest transparent
for (( i=0;i<numcolors; i++)); do
	convert \( -size ${ww}x${hh} xc:"${newcolorArr[$i]}" \) $dir/tmpM$i.miff \
		-compose copy_opacity -composite $dir/tmpS$i.miff
done

# create imagelist
imagelist=""
for (( i=0;i<numcolors; i++)); do
	imagelist="$imagelist $dir/tmpS$i.miff"
done

# do CCL processing to merge small areas in to surrounding/neighboring clusters
if [ $area -gt 0 ]; then
	if [ "$im_version" -lt "06090209" ]; then
	
		# increase area by 1, since CCL uses smallest area to save rather than largest area to remove
		area=$((area+1))

		# flatten images
		convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 -flatten $dir/tmpI.miff

		# Do CCL to merge anything less than or equal to given area and colorize
		Arr=(`convert $dir/tmpI.miff \
			-define connected-components:verbose=true \
			-define connected-components:area-threshold=$area \
			-connected-components 8 \
			-depth 16 $dir/tmpI.miff |\
			tail -n +2 | sed -n 's/^[ ]*\(.*\)[:].*srgb\(.*\)$/\1_srgb\2/p'`)
		num=${#Arr[*]}
		for ((i=0; i<num; i++)); do
		index=`echo ${Arr[$i]} | cut -d\_ -f1`
		color=`echo ${Arr[$i]} | cut -d\_  -f2`
		pct=`convert -precision 15 xc: -format "%[fx:100*$index/quantumrange]" info:`
		#echo "i=$i; num=$num; index=$index; pct=$pct; color=$color;"
		convert $dir/tmpI.miff -depth 16 -fill "$color" -opaque "gray($pct%)" $dir/tmpI.miff
		done
	
			# create colormap for -remap due to error in reporting CCL colors after an area merge
			# remove this and remap below when bug is fixed in CCL
			str=""
			for ((i=0; i<numcolors; i++)); do
			color=${colorArr[$i]}
			pixel="xc:'$color'"
			str="$str $pixel"
			done
			#echo "$str"
			eval 'convert -size 1x1 '$str' +append $dir/lut.miff'

			# remap the colors due to error in merged color reporting in CCL
			convert $dir/tmpI.miff +dither -remap $dir/lut.miff -depth 8 $dir/tmpI.miff
	
		# re-create one image/layer per color
		for ((i=0; i<numcolors; i++)); do
		convert $dir/tmpI.miff -depth 8 -channel rgba -fill none +opaque "${colorArr[$i]}" $dir/tmpS$i.miff
		done


		convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 $flattening $dir/tmpI.miff
		convert $dir/tmpI.miff "$outfile"


		# show final colors
		sortedfinalcolors=`convert $dir/tmpI.miff -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,#\2/p' | sort -r -n -k 1 -t ","`
		echo "count,hexcolor"
		echo "$sortedfinalcolors"
		if [ "$view" = "swatches" -o "$view" = "all" ]; then
			swatch_list=""
			for item in $sortedfinalcolors; do
				color=`echo "$item" | cut -d, -f2`
				pixel="xc:'$color'"
				swatch_list="$swatch_list $pixel"
				echo "swatch_list=$swatch_list"
			done
			eval 'convert '$swatch_list' +append -scale 5000% show:'
		fi
	
	else

		# increase area by 1, since CCL uses smallest area to save rather than largest area to remove
		area=$((area+1))

		# flatten images
		convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 -flatten $dir/tmpI.miff

		# Do CCL to merge anything less than or equal to given area and colorize
#		convert $dir/tmpI.miff -define connected-components:verbose=true \
		convert $dir/tmpI.miff \
		-define connected-components:area-threshold=$area \
		-define connected-components:mean-color=true \
		-connected-components 8 \
		-depth 8 $dir/tmpI.miff	

		# separate colorized images to form final layered images
		if [ "$type" = "layered" ]; then
			convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 -flatten $dir/tmpI.miff
			convert $imagelist -set colorspace $colorspace -colorspace sRGB $adjoining $compressing "$outfile"
		else
			convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 -flatten $dir/tmpI.miff
			if [ "$last_char" = "a" ]; then
				convert $dir/tmpI.miff $dir/tmpA.miff -alpha off -compose copy_opacity -composite "$outfile"
			else
				convert $dir/tmpI.miff $compressing "$outfile"
			fi
		fi


		# show final colors
		sortedfinalcolors=`convert $dir/tmpI.miff -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,#\2/p' | sort -r -n -k 1 -t ","`
		echo "count,hexcolor"
		echo "$sortedfinalcolors"
		if [ "$view" = "swatches" -o "$view" = "all" ]; then
			swatch_list=""
			for item in $sortedfinalcolors; do
				color=`echo "$item" | cut -d, -f2`
				pixel="xc:'$color'"
				swatch_list="$swatch_list $pixel"
				echo "swatch_list=$swatch_list"
			done
			eval 'convert '$swatch_list' +append -scale 5000% show:'
		fi
	fi

else

	# separate colorized images to form final layered images
	if [ "$type" = "layered" ]; then
		# flatten images to use for sortedfinalcolors
		convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 -flatten $dir/tmpI.miff
		convert $imagelist -set colorspace $colorspace -colorspace sRGB $adjoining $compressing "$outfile"
	else
		# flatten images
		convert $imagelist -set colorspace $colorspace -colorspace sRGB -depth 8 -flatten $dir/tmpI.miff
		if [ "$last_char" = "a" ]; then
			convert $dir/tmpI.miff $dir/tmpA.miff -alpha off -compose copy_opacity -composite "$outfile"
		else
			convert $dir/tmpI.miff $compressing "$outfile"
		fi
	fi


	# show final colors
	sortedfinalcolors=`convert $dir/tmpI.miff -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,#\2/p' | sort -r -n -k 1 -t ","`
	if [ "$view" = "dominant" ]; then
		dominantcolor=`echo "$sortedfinalcolors" | head -n 1 | cut -d, -f2`
		echo "$dominantcolor"
	else
		echo "final colors:"
		echo "count,hexcolor"
		echo "$sortedfinalcolors"
	fi
	if [ "$view" = "swatches" -o "$view" = "all" ]; then
		swatch_list=""
		for item in $sortedfinalcolors; do
			color=`echo "$item" | cut -d, -f2`
			pixel="xc:'$color'"
			swatch_list="$swatch_list $pixel"
		done
		eval 'convert '$swatch_list' +append -scale 5000% show:'
	fi
			
fi

exit 0
