[magick-users] adaptive sharpening - the wonders of the 'fx' command

Kornelis Sietsma korny at sietsma.com
Mon Apr 26 17:35:51 PDT 2004


Hi all - I've been playing with a smart sharpening workflow I found on the 
net, and I've managed to get it working with ImageMagick, thanks to the 'fx' 
command - I thought I'd share it with you, and see if anyone can give me any 
tips for improving the process.

The original technique comes from 
http://www.gimpguru.org/Tutorials/SmartSharpening2/ - I wanted to replace this 
manual Gimp process with an ImageMagick equivalent, partly because I wanted to 
manipulate 48-bit digital camera images, and partly so I could automatically 
bulk sharpen a pile of photos at once.

The basic original technique is :
1 - Create an edge mask by running an edge-detect on the image, converting to 
greyscale, blurring the results, and spreading the contrast out a bit.
2 - Split the image into HSV channels
3 - Strongly sharpen the V channel using unsharp mask
4 - Merge the sharpened V channel back with the H and S channels, using the 
edge mask as a mask.

This means that areas near edges in the original image get sharpened quite 
strongly, while areas far from edges get left largely unprocessed.

Due to a lack of HSV channel manipulation in ImageMagick I couldn't do this 
quite the same way - there is no way (that I could find) to do step 4 without 
resorting to some mathematics.  But the rest of the steps were fairly easy:

1. With some fiddling of parameters, I make an edge mask with:
   convert orig.png -edge 3 -colorspace GRAY -level 20%,95% -gaussian 10 
-level 10%,95% edgemask.png

2. I managed to extract just a brightness image with :
   convert orig.png -modulate 100,0 bchannel.png
(This is close enough to the "V" channel for my purposes - I thought of using 
"intensity" but that was rather too slow for my liking)

3. Sharpening is simple, though again lots of fiddling of parameters can be 
done.  Note this is stronger sharpening than you'd want to do normally!
   convert bchannel.png -unsharp 0x1+200+0 sharpened.png

4. Merging them back together is where 'fx' comes in:
   convert orig.png bchannel.png sharpened.png edgemask.png -fx 
"u[0]+(((u[2]+1)/(u[1]+1))-1)*u[0]*u[3]" output.png

just to break that last mess down:
u[0] is the original image
u[1] is the brightness channel
u[2] is the sharpened brightness channel
u[3] is the edge mask
((u[2]+1)/(u[1]+1)) is the ratio of the sharpened brightness to the original - 
I had to use "((u[2]+1)/(u[1]+1))" instead of "(u[2]/u[1])" as the latter 
would cause divide-by-zero problems on black areas of the original image. 
(I'll call this "K" from here on for simplification.)

The rest is to scale the amount of brightness change by the edge mask (u[3]):
when u[3] is 0, the output is "u[0]"
when u[3] is 1, the output is "u[0] + (K-1)*u[0]"
    which equals "K * u[0]"

Finally, I string the whole thing together into a single command line:

convert orig.png \( +clone -modulate 100,0 \) \( +clone -unsharp 0x1+200+0 \) 
\( -clone 0 -edge 3 -colorspace GRAY -level 20%,95% -gaussian 10 -level 
10%,95% \) -colorspace RGB -fx "u[0]+(((u[2]+1)/(u[1]+1))-1)*u[0]*u[3]" output.png

Note I had to put an extra "-colorspace RGB" in there to stop the output being 
greyscale.

It's kind of slow on a big image, but it works!

Thoughts, comments, improvements?

- Korny
-- 
Kornelis Sietsma  korny at my_surname.com


More information about the Magick-users mailing list