├── Align.sh ├── Deadpixels.sh ├── RAW_convert.sh ├── README.md ├── README.txt ├── WB.sh ├── compile.sh ├── dcraw.c ├── deadpixels.c ├── slabs.sh └── unsharp.sh /Align.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Written by Sergey Mashchenko 4 | 5 | # Aligning focus stack, starting from the middle frame, and running two processes in parallel in the opposite directions. 6 | # This ensures good framing for the aligned stack (minimizes frame waste) and accelerates the computations by 50-100%. 7 | # Creates a set of aligned images with the names OUT0000.tif, OUT0001.tif and so on. 8 | # If something goes wrong you might need to kill one or both running align_image_stack processes manually using 9 | # pkill or kill. 10 | 11 | 12 | echo 13 | if test $# -lt 2 14 | then 15 | echo "Syntax: Align.sh [-l] image1 image2 [image3 ...]" 16 | echo 17 | echo -l: assume that the images have linear color space 18 | echo 19 | exit 20 | fi 21 | 22 | if test "$1" = "-l" 23 | then 24 | echo "Assuming linear color space" 25 | OPT="$1" 26 | else 27 | OPT="-m" 28 | fi 29 | 30 | files=("$@") 31 | N=$# 32 | middle=$(($N / 2 - 1)) 33 | echo N=$N, middle=$middle 34 | echo 35 | 36 | # Reversing the order of files in the first half: 37 | for e in "${files[@]:0:$middle+1}" 38 | do 39 | revfiles=( "$e" "${revfiles[@]}" ) 40 | done 41 | 42 | 43 | # First half aligning: 44 | align_image_stack "$OPT" --use-given-order -m -a P1_ ${revfiles[@]} &>out1.log & 45 | 46 | # A 10s delay, to have a phase shift between two parallel processes: 47 | sleep 10 48 | 49 | 50 | # Second half aligning: 51 | align_image_stack "$OPT" --use-given-order -m -a P2_ ${files[@]:$middle} &>out2.log & 52 | 53 | # Waiting for both processes to finish: 54 | wait 55 | 56 | # Deleting the first file in the second half as it is identical to the last file in the first half: 57 | \rm P2_0000.tif 58 | 59 | # Renaming the outputs to become a single aligned stack 60 | for name in P1_* 61 | do 62 | N1=`echo $name |cut -b 4-7` 63 | N2=`echo $middle $N1 | awk '{printf "%04d\n", $1-$2}'` 64 | mv $name OUT${N2}.tif 65 | done 66 | 67 | for name in P2_* 68 | do 69 | N1=`echo $name |cut -b 4-7` 70 | N2=`echo $middle $N1 | awk '{printf "%04d\n", $1+$2}'` 71 | mv $name OUT${N2}.tif 72 | done 73 | 74 | echo 75 | echo "Success!" 76 | echo 77 | -------------------------------------------------------------------------------- /Deadpixels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Now works with either single or multiple dark frames. When multiple images are provided, they are averaged first (written as dark.tiff file). 4 | # Written by Sergey Mashchenko 5 | 6 | # Bash script to generate deadpixels.txt file (list of coordinates for all dead and hot pixels) using provided dark frame. 7 | 8 | N=$# 9 | 10 | echo 11 | if test $N -eq 0 12 | then 13 | echo "Syntax: Deadpixels.sh dark_frame_raw_image[s]" 14 | echo 15 | exit 16 | fi 17 | 18 | rm -f dark_*.tiff 19 | 20 | for ((i=0; i<$N; i++)) 21 | do 22 | # Converting raw dark frame(s) to 16-bit gray scale TIFF (linear color space): 23 | echo "Converting $1" 24 | dcraw -4 -T -j -t 0 -D -c $1 > dark_${i}.tiff 25 | shift 26 | done 27 | 28 | if test $N -eq 1 29 | then 30 | \mv dark_0.tiff dark.tiff 31 | else 32 | # If multiple dark frame provided, averaging them using ImageMagick: 33 | magick convert dark_*.tiff -evaluate-sequence mean dark.tiff 34 | fi 35 | 36 | # Using deadpixels program to find all dead and hot pixels (using Nsigma=10): 37 | # Reduce Nsigma if not all hot pixels are detected (but don't make it smaller than 5.5) 38 | # Increase Nsigma if spurious hot pixels are detected (but likely the problem is that your dark frame is not 39 | # entirely dark) 40 | deadpixels dark.tiff 4 41 | 42 | 43 | if test -f ~/deadpixels.txt 44 | then 45 | echo 46 | echo "~/deadpixels.txt already exists." 47 | echo "Do you want to overwrite it (y/n)?" 48 | read p 49 | if test "$p" = "y" -o "$p" = "Y" 50 | then 51 | # Copying the deadpixels.txt file to home directory (overwriting the old file present there): 52 | \cp deadpixels.txt ~ 53 | fi 54 | fi 55 | -------------------------------------------------------------------------------- /RAW_convert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Written by Sergey Mashchenko 4 | 5 | # Bash script to convert raw images (CR2, DNG etc.) to 48-bit TIFF images. 6 | # It can use either sRGB or linear color space, and can optionally accept custom white balance coefficients 7 | # (computed by applying another script - WB.sh - to a raw photograph of a gray card). 8 | # If dark.tiff present in the local folder, it will be subtracted from the image(s), before debayering. 9 | 10 | if test $# -lt 1 11 | then 12 | echo 13 | echo "Syntax:" 14 | echo " RAW_convert.sh [-l] [-r ] image1 [image2 image3 ...]" 15 | echo 16 | echo "-l: use linear color space" 17 | echo "-r : use custom white balance coefficients r, g, b, g" 18 | echo 19 | exit 20 | fi 21 | 22 | # Processing optional switches 23 | args=("$@") 24 | arg_r=-1 25 | arg_l=-1 26 | for i in 0 1 5 27 | do 28 | if test "${args[$i]}" = "-l" 29 | then 30 | arg_l=$i 31 | fi 32 | if test "${args[$i]}" = "-r" 33 | then 34 | arg_r=$i 35 | fi 36 | done 37 | 38 | if test $arg_l -ge 0 39 | then 40 | echo "Using linear color space" 41 | OPT="-4" 42 | else 43 | echo "Using sRGB color space" 44 | OPT="-6 -W" 45 | fi 46 | 47 | if test $arg_r -ge 0 48 | then 49 | echo "Using custom white balance" 50 | OPT2="${args[$arg_r]} ${args[$(($arg_r+1))]} ${args[$(($arg_r+2))]} ${args[$(($arg_r+3))]} ${args[$(($arg_r+4))]}" 51 | else 52 | echo "Using system white balance" 53 | OPT2="" 54 | fi 55 | 56 | if test $arg_l -ge 0 57 | then 58 | shift 59 | fi 60 | if test $arg_r -ge 0 61 | then 62 | shift 5 63 | fi 64 | 65 | # Copying the deadpixels.txt file if present: 66 | if test -f ~/deadpixels.txt 67 | then 68 | \cp ~/deadpixels.txt . 69 | dead_arg="-P deadpixels.txt" 70 | else 71 | dead_arg="" 72 | fi 73 | 74 | if test -f dark.tiff 75 | then 76 | magick convert dark.tiff dark.pgm 77 | # Subtracting a dark image if present in the current directory: 78 | OPT3="-K dark.pgm" 79 | fi 80 | 81 | echo "dcraw arguments: $dead_arg $OPT $OPT2 $OPT3" 82 | 83 | # RAW images conversion to 48-bit TIFFs: 84 | dcraw $dead_arg $OPT $OPT2 $OPT3 -T $* 85 | 86 | echo 87 | echo "Success!" 88 | echo 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Macro-scripts 2 | A set of BASH scripts and C++ programs representing a complete workflow for processing macro focus stacking photographs. Utilizes other open source packages (dcraw, Hugin, ImageMagick) internally. The Deadpixels script (automatic detection of dead and hot pixels in raw photographs) can be of use for general purpose photography, not just for macro photography. 3 | 4 | The package should work under any Linux distro and under Cygwin (Windows). It will likely work under MacOS (not tested). 5 | 6 | Consult the included README.txt file for installation instructions. 7 | 8 | Detailed user guide can be found here: 9 | 10 | http://pulsar124.wikia.com/wiki/Open_Source_workflow_for_macro_focus_stacking 11 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Author: Sergey Mashchenko 2 | 3 | A set of bash scripts for post-processing of focus stacks for macro photography. Utilizes open source programs 4 | dcraw (https://www.cybercom.net/~dcoffin/dcraw/), Hugin (http://hugin.sourceforge.net/), and 5 | ImageMagick (http://www.imagemagick.org/script/index.php). Contains one C++ program written by the author (deadpixels.c). 6 | 7 | The scripts use BASH shell, so should work under any Linux distro and Cygwin under Windows. 8 | 9 | Assuming the directory Macro_scripts is located in your home directory, put the following line at the end of your ~/.bashrc file: 10 | 11 | export PATH=~/Macro-scripts-master:$PATH 12 | 13 | For Cygwin (under Windows), you will need to install additional packages, including gcc-core, gcc-g++, libgcc1, ImageMagick, 14 | all libMagick* modules, liblcms2 and liblcms2-devel, libjpeg and libjpeg-devel. Install the Windows binary of Hugin, and 15 | add the Cygwin path to the Windows binary at the end of ~/.bashrc file, e.g.: 16 | 17 | export PATH=/cygdrive/c/Program\ Files/Hugin/bin/:$PATH 18 | 19 | You need Hugin-2015 or newer version. 20 | 21 | You have to make all the scripts executable by running the following command inside ~/Macro-scripts-master : 22 | 23 | chmod u+x *.sh 24 | 25 | To compile the two executables (dcraw and deadpixels), execute the script compile.sh (for both Linux and Cygwin). 26 | 27 | For more details, consult the wikia page: 28 | 29 | http://pulsar124.wikia.com/wiki/Open_Source_workflow_for_macro_focus_stacking 30 | -------------------------------------------------------------------------------- /WB.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Written by Sergey Mashchenko 4 | 5 | # Bash script to compute white balance settings for dcraw, using central area in a raw grey card image 6 | 7 | if test $# -ne 1 8 | then 9 | echo 10 | echo "Syntax: WB.sh grey_card_raw_image" 11 | echo 12 | exit 13 | fi 14 | 15 | # Fraction of the image to use for white balance calculations (in both dimensions; centered) 16 | frac=0.3 17 | 18 | # Copying the deadpixels.txt file if present: 19 | if test -f ~/deadpixels.txt 20 | then 21 | \cp ~/deadpixels.txt . 22 | dead_arg="-P deadpixels.txt" 23 | else 24 | dead_arg="" 25 | fi 26 | 27 | # Obtaining the image dimensions: 28 | read Nx Ny <<< $(dcraw -i -v $1 |grep "^Image size"|cut -d: -f2|sed 's/x//g') 29 | # Center coordinates: 30 | x=$(($Nx/2)) 31 | y=$(($Ny/2)) 32 | # Crop dimensions: 33 | w=`echo $x $frac | awk '{print int($1*$2)}'` 34 | h=`echo $y $frac | awk '{print int($1*$2)}'` 35 | 36 | echo 37 | echo "Image dimensions: $Nx x $Ny" 38 | echo "Crop area center and dimensions: x,y=$x,$y; w,h=$w x $h" 39 | echo 40 | 41 | # Computing white balance 42 | wb=`dcraw $dead_arg -v -A $x $y $w $h -c $1 2>&1 >/dev/null | grep "^multipliers" | cut -d" " -f2-` 43 | 44 | echo "White balance (arguments for -r switch of dcraw):" 45 | echo $wb 46 | echo 47 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Written by Sergey Mashchenko 4 | 5 | # Execute this script before using Macro scripts. 6 | 7 | if test ! -f deadpixels -a ! -f deadpixels.exe 8 | then 9 | echo "Compiling deadpixels..." 10 | gcc `Wand-config --cflags --cppflags` -O4 -o deadpixels deadpixels.c `Wand-config --ldflags --libs` -lm 11 | fi 12 | 13 | if test ! -f dcraw -a ! -f dcraw.exe 14 | then 15 | echo "Compiling dcraw..." 16 | gcc -DNO_JASPER -o dcraw -O4 dcraw.c -lm -ljpeg -llcms2 17 | fi 18 | -------------------------------------------------------------------------------- /deadpixels.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 8 | Written by Sergey Mashchenko 9 | 10 | Utilizes ImageMagick library. 11 | 12 | Program to find all hot and dead pixels in a given image (dark frame; gray scale). 13 | The dark frame should be generated as follows: 14 | 15 | dcraw -4 -T -j -t 0 -D dark.dng 16 | 17 | Compiling the program (Linux and Cygwin): 18 | 19 | gcc `Wand-config --cflags --cppflags` -O4 -o deadpixels deadpixels.c `Wand-config --ldflags --libs` -lm 20 | 21 | */ 22 | 23 | 24 | int main(int argc,char **argv) 25 | { 26 | #define ThrowWandException(wand) \ 27 | { \ 28 | char \ 29 | *description; \ 30 | \ 31 | ExceptionType \ 32 | severity; \ 33 | \ 34 | description=MagickGetException(wand,&severity); \ 35 | (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \ 36 | description=(char *) MagickRelinquishMemory(description); \ 37 | exit(-1); \ 38 | } 39 | 40 | long 41 | y, Ntot; 42 | 43 | long 44 | k, Nx, Ny, Npix, Npix_old, Ndead, Nhot; 45 | 46 | MagickBooleanType 47 | status; 48 | 49 | MagickPixelPacket 50 | pixel; 51 | 52 | MagickWand 53 | *image_wand; 54 | 55 | PixelIterator 56 | *iterator; 57 | 58 | PixelWand 59 | **pixels; 60 | 61 | register long 62 | x; 63 | 64 | size_t 65 | width; 66 | 67 | FILE 68 | *fp; 69 | 70 | double 71 | sum, sum2, p0, sgm, p, Nsigma; 72 | 73 | // Threshold for dead pixels: 74 | const double 75 | dead = 1e-6; 76 | 77 | 78 | if (argc==1) 79 | { 80 | printf("Usage: %s dark_frame [Nsigma]\n",argv[0]); 81 | printf("If omitted, Nsigma=10\n\n"); 82 | printf("Generate dark_frame using the following command:\n\n"); 83 | printf(" dcraw -4 -T -j -t 0 -D raw_dark_frame\n\n"); 84 | exit(0); 85 | } 86 | 87 | if (argc==3) 88 | Nsigma = atof(argv[2]); 89 | else 90 | Nsigma = 10; 91 | printf ("Nsigma=%f\n", Nsigma); 92 | 93 | /* 94 | Read the image. 95 | */ 96 | 97 | 98 | MagickWandGenesis(); 99 | image_wand=NewMagickWand(); 100 | status=MagickReadImage(image_wand,argv[1]); 101 | if (status == MagickFalse) 102 | ThrowWandException(image_wand); 103 | 104 | // Image size: 105 | Nx = MagickGetImageWidth(image_wand); 106 | Ny = MagickGetImageHeight(image_wand); 107 | 108 | 109 | p0 = 0.0; 110 | sgm = 1e12; 111 | Npix = -1; 112 | Npix_old = -2; 113 | k = 0; 114 | 115 | // Iteratively computing sigma for dark frame pixels 116 | while (Npix != Npix_old) 117 | { 118 | k++; 119 | iterator=NewPixelIterator(image_wand); 120 | if ((iterator == (PixelIterator *) NULL)) 121 | ThrowWandException(image_wand); 122 | Npix_old = Npix; 123 | sum = 0.0; 124 | sum2 = 0.0; 125 | Npix = 0; 126 | for (y=0; y < (long) MagickGetImageHeight(image_wand); y++) 127 | { 128 | pixels=PixelGetNextIteratorRow(iterator,&width); 129 | if ((pixels == (PixelWand **) NULL)) 130 | break; 131 | for (x=0; x < (long) width; x++) 132 | { 133 | 134 | PixelGetMagickColor(pixels[x],&pixel); 135 | p = pixel.green; 136 | 137 | // Discarding dead pixels, and using three sigma rule: 138 | if (p > dead && abs(p-p0)<3*sgm) 139 | { 140 | sum = sum + p; 141 | sum2 = sum2 + p * p; 142 | Npix++; 143 | } 144 | } // x cycle 145 | } // y cycle 146 | 147 | p0 = sum / Npix; 148 | sgm = sqrt(sum2/Npix - p0*p0); 149 | printf ("Iteration %d; p=%e, sgm=%e, N=%d\n", k, p0, sgm, Npix); 150 | 151 | if (y < (long) MagickGetImageHeight(image_wand)) 152 | ThrowWandException(image_wand); 153 | iterator=DestroyPixelIterator(iterator); 154 | } 155 | 156 | 157 | // Discovering all dead and hot pixels, and writing them to deadpixels.txt file 158 | fp = fopen("deadpixels.txt", "w"); 159 | Ndead = 0; 160 | Nhot = 0; 161 | iterator=NewPixelIterator(image_wand); 162 | if ((iterator == (PixelIterator *) NULL)) 163 | ThrowWandException(image_wand); 164 | for (y=0; y < (long) MagickGetImageHeight(image_wand); y++) 165 | { 166 | pixels=PixelGetNextIteratorRow(iterator,&width); 167 | if ((pixels == (PixelWand **) NULL)) 168 | break; 169 | for (x=0; x < (long) width; x++) 170 | { 171 | 172 | PixelGetMagickColor(pixels[x],&pixel); 173 | p = pixel.green; 174 | 175 | if (p < dead) 176 | Ndead++; 177 | if (p-p0 > Nsigma*sgm) 178 | Nhot++; 179 | 180 | // Detecting dead and hot pixels: 181 | if (p < dead) 182 | { 183 | // Dead pixels are marked with the timestamp=0 184 | fprintf (fp, "%d %d 0\n", x, y); 185 | } 186 | else if (p-p0 > Nsigma*sgm) 187 | { 188 | // Hot pixels are marked with the timestamp=1 !!! removed this feature, as new dcraw dosn't work with this 189 | fprintf (fp, "%d %d 0\n", x, y); 190 | } 191 | } // x cycle 192 | } // y cycle 193 | if (y < (long) MagickGetImageHeight(image_wand)) 194 | ThrowWandException(image_wand); 195 | iterator=DestroyPixelIterator(iterator); 196 | 197 | fclose(fp); 198 | 199 | printf("\n Ndead=%d\n Nhot=%d\n Ntotal=%d\n", Ndead, Nhot, Ndead+Nhot); 200 | 201 | image_wand=DestroyMagickWand(image_wand); 202 | 203 | MagickWandTerminus(); 204 | return(0); 205 | } 206 | 207 | -------------------------------------------------------------------------------- /slabs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Written by Sergey Mashchenko 4 | 5 | # Focus stacking with enfuse using a two-stage process (first creating slabs, and then stacking the slabs) 6 | # All files in the current directory with names OUT*.tif (output of Align.sh script) will be processed 7 | # If any command line argument used, will skip the enfuse part (dry run; for debugging) 8 | 9 | # Overlap on each side (fraction), for each slab: 10 | over=0 11 | # Overlap should be at least that many images: 12 | Nover_min=0 13 | 14 | # Creating the list of tiff images to process: 15 | /usr/bin/ls -1 OUT*.tif 2>/dev/null > List 16 | 17 | # Number of input files: 18 | N=`cat List|wc -l` 19 | if test $N -eq 0 20 | then 21 | echo "No files to process; exiting" 22 | exit 23 | fi 24 | 25 | N1=$(($N-1)) 26 | 27 | # Size of each slab (not including the overlap) 28 | Size=`echo $N| awk '{print int(sqrt($1))}'` 29 | # N overlap is at least $Nover_min: 30 | Nover=`echo $Size $over $Nover_min|awk '{A=int($1*$2); if (A<$3) print $3; else print A; fi}'` 31 | 32 | # Last (usually smaller) slab size: 33 | Slast=$(($N%$Size-$Nover)) 34 | # Number of complete slabs: 35 | Nslabs=$(($N/$Size)) 36 | if test $Slast -lt 0 37 | then 38 | Nslabs=$(($Nslabs-1)) 39 | Slast=$(($N-$Nslabs*$Size-$Nover)) 40 | fi 41 | 42 | echo "Size=$Size, Nslabs=$Nslabs, Slast=$Slast, Nover=$Nover" 43 | echo 44 | j=0 45 | 46 | 47 | # First stage (creating multiple slabs) 48 | for ((i=0; i<$Nslabs; i++)) 49 | do 50 | # First file to include in the slab: 51 | k1=$(($i*$Size+$j)) 52 | if test $j -lt $Slast 53 | then 54 | j=$(($j+1)) 55 | fi 56 | # Last file to include in the slab: 57 | k2=$((($i+1)*$Size+$j+$Nover-1)) 58 | if test $k2 -gt $N1 59 | then 60 | k2=$N1 61 | fi 62 | echo Slab=$i, range $k1 - $k2, $(($k2-$k1+1)) frames 63 | K1=$(($k1+1)) 64 | K2=$(($k2+1)) 65 | if test $# -eq 0 66 | then 67 | enfuse --exposure-weight=0 --saturation-weight=0 --contrast-weight=1 --hard-mask --gray-projector=l-star --output=`printf '%04d' $i`.tif `cat List | sed -n ${K1},${K2}p` 68 | fi 69 | done 70 | 71 | 72 | # Second stage - merging all slabs into final stacked photo 73 | echo 74 | echo "Second stage: stacking the slabs" 75 | if test $# -eq 0 76 | then 77 | enfuse --exposure-weight=0 --saturation-weight=0 --contrast-weight=1 --hard-mask --gray-projector=l-star --output=output.tif ????.tif 78 | if test $? 79 | then 80 | echo 81 | echo "Success!" 82 | echo 83 | fi 84 | fi 85 | 86 | 87 | -------------------------------------------------------------------------------- /unsharp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Part of Macro-scripts package (a complete Open Source workflow for processing macro focus stacking photographs) 3 | # Written by Sergey Mashchenko 4 | 5 | # Unsharp masking for macro shots, using three different unsharp scales 6 | 7 | # Good numbers: 4:0.5:0.5 8 | 9 | # Radii for the three scales (pixels): 10 | #rad_x=24 11 | rad_x=22 12 | #rad_y=6 13 | rad_y=6 14 | # 1.5: 15 | rad_z=2 16 | # Default strength for each scale: 17 | s_x=0.05 18 | s_y=0.15 19 | # 1: 20 | s_z=1 21 | 22 | echo 23 | if test $# -eq 0 24 | then 25 | echo "Syntax: unsharp.sh [strength] in_file out_file" 26 | echo 27 | echo "If 'strength' is skipped, it is assumed to be 1." 28 | echo "If 'strength' is a single number, all spatial scales will be sharpened by the same amount (given by that number)." 29 | echo "If 'strength' has the following form - x:y:z - the largest scale will be sharpened using 'x' strength," 30 | echo " the middle scale will use 'y', and the smallest scale will use 'z'." 31 | echo 32 | exit 33 | fi 34 | 35 | if test $# -eq 2 36 | then 37 | x=1 38 | y=1 39 | z=1 40 | IN="$1" 41 | OUT="$2" 42 | else 43 | IN="$2" 44 | OUT="$3" 45 | N=`echo $1 |grep : |wc -l ` 46 | if test $N -eq 0 47 | then 48 | x=$1 49 | y=$1 50 | z=$1 51 | else 52 | x=`echo $1 | cut -d: -f1` 53 | y=`echo $1 | cut -d: -f2` 54 | z=`echo $1 | cut -d: -f3` 55 | fi 56 | fi 57 | 58 | echo "Using the large/middle/small scale sharpening strengths $x, $y, $z" 59 | echo 60 | 61 | # Unsharp masking, done in the following order: large scale, middle scale, small scale: 62 | convert "$IN" -unsharp 0x$rad_x+`echo $x $s_x | awk '{print $1*$2}'`+0 -unsharp 0x$rad_y+`echo $y $s_y | awk '{print $1*$2}'`+0 -unsharp 0x$rad_z+`echo $z $s_z | awk '{print $1*$2}'`+0 "$OUT" 63 | --------------------------------------------------------------------------------