Sharpening using Image Magick
Summary: an explanation of Image Magick’s unsharp masking parameters, and how the filter compares to the unsharp mask filters in Photoshop and the GIMP.
Image Magick is a set of software tools for processing digital images. The package is open-source, freely-available and may be freely distributed. It is a particularly powerful and flexible package for building custom image processing scripts because the command-line tools can be called from a script, or as library routines from special scripting versions of Perl, Python, and other high level programming languages. Many people, myself included, have scratched our collective heads trying to figure out Image Magick’s unsharp mask operator. The command has extremely sparsely documented parameters and (possibly) poor choices for default values, leading to a lot of frustration and confusion on the part of users of the package. This page is an attempt to shed some light on the parameters and operation of Image Magick’s unsharp mask and to compare it to a couple of other well-used unsharp mask filters in Photoshop and The GIMP.
If you need an introduction to the general concept of unsharp masking, you should look elsewhere for additional tutorials on the subject; I only briefly review the concepts in here. This tutorial is mostly for those who already understand the basics of unsharp masking and want to understand how to manipulate and interpret the parameters of the operator in Image Magick. I.M. does a very nice job with unsharp masking once you understand the parameters and how to use them effectively.
Invoking the unsharp mask
Most users will use the unsharp mask filter in the convert command. The option to invoke an unsharp mask looks like this
That is, a radius is expected (or a leading “x” if omitted), followed by optional parameters sigma, amount and threshold. [Note that there is also a -sharpen option to convert. This is not an alias for -unsharp, and (I'm pretty sure) employs a different sharpening routine internally.]
A typical call to convert might look something like the following:
$ convert ... -unsharp 1.5x1.2+1.0+0.10 <input file> <output file>
The “-unsharp” option should usually come last (after other options), since in Image Magick operations are carried out in the order that they appear on the command line, and sharpening is usually the last step that you want to take before image output. Missing parameters to the unsharp mask will take on default values, which may not be the ones you want. I strongly recommend that you always specify all four parameters to prevent ambiguity.
Notes on parameters and operation
The radius parameter
The radius parameter specifies (official documentation)
“the radius of the Gaussian, in pixels, not counting the center pixel”
Unsharp masking, like many other image-processing filters, is a convolution kernel operation. The filter processes the image pixel by pixel. For each pixel it examines a block of pixels surrounding it (the kernel) and does some calculations on them to render the output pixel value. The radius parameter determines which pixels surrounding the center pixel will be considered in the convolution kernel: (think of a circle) the larger the radius, the more pixels that will need to be processed for each individual pixel.
Image Magick’s radius is similar to the same parameter in Photoshop, GIMP and other image editors. In practical terms, it affects the size of the “halos” created to increase contrast along the edges in the image, increasing acutance and thus apparent sharpness.
How do you know how big of a radius to use? It depends on your output target resolution, for one thing. It also depends on your personal preferences, as well as the specific needs of the image at hand. As far as the resolution issue goes, the GIMP User Manual recommends that unsharp mask radius be set as follows:
radius = (output ppi / 30) * 0.2
Which is very similar to another commonly found rule of thumb:
radius = output ppi / 150
So for a monitor with 72 PPI resolution, you’d use a radius of approximately 0.5; if your targeting a printer at 300 PPI you’d use a value of 2.0. Use these as a starting point; different images have different sharpening requirements, and individual preference is also a consideration. [Aside: there are a few postings around the net (including some referenced in this article) that suggest that Image Magick accepts, but does not honor, fractional radii; that is, if you specify a radius of 0.5 or 1.2 it is rounded, or defaults to an integer, or is silently ignored, etc. This is not true, at least as of version 5.4.7, which is the one that I am using as I write this article. You can easily see for yourself by doing something like the following:
$ convert -unsharp 1.2x1.2+5+0 test.tif testo1.tif $ convert -unsharp 1.4x1.4+5+0 test.tif testo2.tif $ composite -compose difference test01.tif testo2.tif diff.tif $ display diff.tif
you can also load them into the GIMP or Photoshop into different layers and change the blend mode to "Difference"; the resulting image is not black (you may need to look closely for a 0.2 difference in radius). No, this mistaken impression likely comes from the fact that there is a relationship between the radius and sigma parameters, and if you do not specify sigma properly in relation to the radius, the radius may indeed be changed, or at least not work as expected. Read on for more on this.]
Please note that the default radius (if you do not specify anything) is 0, a special value which tells the unsharp mask algorithm to “select an appropriate value for the radius”!.
The sigma parameter
The sigma parameter specifies (official documentation)
“the standard deviation of the Gaussian, in pixels”
This is the most confusing parameter of the four, probably because it is “invisible” in other implementations of unsharp masking, and it is most sparsely documented. The best explanation I have found for it came from a google search that unearthed an archived mailing list thread which had the following snippet:
>Comparing the results of > > convert -unsharp 1.2x1+4+0 test test1.2x1+4+0 > >and > > convert -unsharp 30x1+4+0 test test30x1+4+0 > >results in no significant differences but the latter takes approx. 50 times >longer to complete. That is not surprising. A radius of 30 involves on the order of 61x61 input pixels in the convolution of each output pixel. A radius of 1.2 involves 3x3 or 5x5 pixels. >Please can anybody give me any hints, what 'sigma' means? It describes the relative weight of pixels as a function of their distance from the center of the convolution kernel. For small sigma, the outer pixels have little weight.
Another important clue comes from the documentation for the -unsharp option to convert (emphasis mine):
The -unsharp option sharpens an image. We convolve the image with a Gaussian operator of the given radius and standard deviation (sigma). For reasonable results, radius should be larger than sigma. Use a radius of 0 to have the method select a suitable radius.
Combining the two clues provides some good insight: sigma is a parameter that gives you some control over how the strength (given by the amount parameter) of the sharpening is “graduated” or lessened as you radiate away from a given pixel at the center of the convolution matrix to the limit defined by the radius. My testing confirms this inferred conclusion, namely that a bigger sigma causes more pronounced sharpening for a given radius. That is why the poster in the mailing list question (above) did not see any significant difference in the sharpening even though he was using an amount of 400% (!!) and a threshold of 0%; with a sigma of only 1.0, the strength of the filter falls off too rapidly to be noticed despite the large difference in radius between the two invocations. This is also why the man page says “for reasonable results, radius should be larger than sigma”; if it is not, then the sigma parameter does not have a graduated effect, as designed, to “soften” the halos toward their edges; instead it simply applies the amount evenly to the edge of the radius (which may be what you want in some circumstances). A general rule of thumb for choosing sigma might be:
if radius < 1, then sigma = radius else sigma = sqrt(radius)
Summary: choose your radius first, then choose a sigma smaller than or equal to that. Experimentation will yield the best results. Please note that the default sigma (if you do not specify anything) is 1.0. This is the main culprit for why most people don’t see as much effect with Image Magick’s unsharp mask operator as they do with other implementations of unsharp mask if they are using a larger radius: unless you bump up this parameter you are not getting the full benefit of the larger radius!
[Aside: you might be wondering what happens if sigma is specifed larger than the radius. The answer, as the documentation states, is that the result may not be "reasonable". In my testing, the usual result is that the sharpening is extended at the specified amount to the edge of the specified radius, and larger values of sigma have little if any effect. In some cases (e.g. for radius < 0) specifying a larger sigma increased the effective radius (e.g. to 1); this may be the result of a "sanity check" on the parameters in the code. In any case, keep in mind that the algorithm is designed for sigma to be less than or equal to the radius, and results may be unexpected if used otherwise.]
The amount parameter
The amount parameter specifies (official documentation)
“the percentage of the difference between the original and the blur image that is added back into the original”
The amount parameter can be thought of as the “strength” of the sharpening: higher values increase contrast in the halos more than lower ones. Very large values may cause highlights on halos to blow out or shadows on them to block up. If this happens, consider using a lower amount with a higher radius instead.
amount should be specified as a decimal value indicating the percentage. So, for example, if in Photoshop you would use an amount of 170 (170%), in Image Magick you would use 1.7.
Please note that the default amount (if you do not specify anything) is 1.0 (i.e. 100%).
The threshold parameter
The threshold parameter specifies (official documentation)
“as a fraction of MaxRGB, needed to apply the difference amount”
The threshold specifies a minimum amount of difference between the center pixel vs. sourrounding pixels in the convolution kernel necessary to apply the local contrast enhancement. Increasing this value causes the algorithm to become less sensitive to differences that may define edges. Specifying a positive threshold is often used to avoid sharpening smooth areas that may contain noise (e.g. an area of blue sky). If you have a noisy image, strongly consider raising the threshold, or using some kind of smart sharpening technique instead.
The threshold parameter should be specified as a decimal value indicating this percentage. This is different than GIMP or Photoshop, which both specify the threshold in actual pixel levels between 0 and the maximum (for 8-bit images, 255).
Please note that the default threshold (if you do not specify anything) is 0.05 (i.e. 5%; this corresponds to a threshold of .05 * 255 = 12-13 in Photoshop). Photoshop uses a default threshold of 0 (i.e. no threshold) and the unsharp masking is applied evenly throughout the image. If that is what you want you will need to specify a 0.0 value for Image Magick’s threshold. This is undoubtedly another source of confusion regarding Image Magick’s sharpening algorithm.
Summary of differences in various unsharp mask filters
|Photoshop||specified in pixels||N/A||specified as % (% notation)||specified as difference in pixel values (as integer)|
|GIMP||specified in pixels||N/A||specified as % (decimal notation)||specified as difference in pixel values (as integer)||Same results as Photoshop for same parameters.|
|Image Magick||specified in pixels||specified in pixels||specified as % (decimal notation)||specified as % difference in pixel values (decimal notation)||Lower strength effect with same amount than with
GIMP or Photoshop, e.g. GIMP (r=4, a=0.75, t=0) seems equivalent to
IM (r=s=4, a=1.0, t=0). GIMP/Photoshop are thus quicker to blow
highlights on edges.