Sharpen images with Perl and GIMP

Image Sharpener


How do you sharpen a digital image? A short introduction to the principles and a Perl plugin for GIMP help amateur digital photographers polish their snapshots in a professional way.

By Michael Schilli

ELEN *, 123RF

If you look at a photograph, you can see at a glance whether or not it is in focus. But what does in focus mean? An image that is in focus has clearly defined transitions from light to dark. A black line with a thickness of just a couple of pixels against a white background is the pinnacle of focus. If the transition between black and white is unsharp - that is, if there is a gradient of dark gray and light gray between the black and white - the line no longer looks crisp. In other words, focus means keeping the light/dark transitions in an image as narrow as possible while at the same time keeping as much contrast as possible.

Photographers can do a number of things to set the stage for creating crisp images. For example, strong, direct sunlight gives contours more contrast than a cloudy sky, which softens up the transitions. Moreover, additional light lets you use a lower ISO setting. Higher ISO values on your camera mean that the sensor produces noisy images that appear grainy and out of focus. Also, it is useful to focus on the main subject of the image: the part of the image the viewer sees first should be sharp, other parts are less sensitive and can be slightly unsharp without the viewer gaining the impression of an out-of-focus image. For example, if the eyes are in focus in a portrait, nobody will worry about the nose being slightly out of focus.

In some cases, accidental focus occurs in the wrong places. For example, most people won't appreciate you capturing the details of wrinkly facial skin in portrait photography. Some fuzziness is preferable in this case, so never take these photographs in direct sunlight. Instead, find a shady place. Soft transitions and less contrast are desirable here, although you might want to sharpen the eyes or mouth in the final shot. If you have used an expensive, digital SLR camera to take RAW images, you will appreciate the benefits of this loss-free storage approach. The difference in sharpness is particularly noticeable when you need to crop the image to focus on a part of it. In contrast, the JPEG format loses fine details and sharpness.

One clever method of finding the crispest image from a series of identical snapshots is to check the file size. Because focused, high-detail transitions are more difficult to compress than unsharp ones, sharper JPG images will typically occupy more memory space. Thus, the largest file in a series is typically also the sharpest.

Retrospective Sharpening

GIMP's sharpening function, Filters | Enhance | Sharpen, is perfect for sharpening parts of an image. Resizing an image for web publishing often involves compromising its focus, giving the image a low-contrast, washed-out look. The slider in GIMP's Sharpen menu has a range of 0 through 100, where values between 20 and 40 typically give you the best results (Figure 1). What this does is to shorten the color and brightness transitions at high contrast points of the image. Higher sharpen values result in excessive noise, or unnatural (digital) looking jumps in brightness.

Figure 1: Applying the "Sharpen" filter with a value of 40 focuses high contrast lines.

Sharpening methods all work along the same principle: An algorithm finds the edges and corners of the image and shortens their light-dark transitions, possibly emphasizing them by making the light sides lighter and the dark sides darker. Discovering edges is important as widespread sharpening will give you unnatural artefacts in slow tonal transitions, such as in faces.

If you look closely at Figure 2, you will see a vertical, red line I added to the lower left part of the image. Figure 3 shows you the brightness values for this test line before and after sharpening. The curve progression in the original is green, and the sharpened pixels are red. GIMP's Sharpen function quite obviously emphasized the light-dark transition, instead of a flat progression, and the graph shows a peak at the transition point in these areas.

Figure 2: Choosing too large an aperture size made the image unsharp.

Figure 3: The sharpened image shows more peaky transitions.

Unsharp Masks

The Unsharp Mask approach takes this one step further by finding transitions and making their dark sides darker, and their lighter sides lighter. This artificially increases the color or brightness transitions at edges and corners and gives viewers an impression of improved focus; however, the real advantage of this approach is the ability to tweak three different parameter buttons to set the intensity of the effect.

Figure 4 shows the GIMP dialog with configurable values for Amount, Radius, and Threshold. The Amount value specifies the contrast enhancement as a percentage. For example, 0.5 reduces the brightness at an edge on the dark side by 50 percent, while increasing it by 50 percent on the light side. A Radius of one or more extends the influence of the filter to the surrounding pixels. If you set a value of 0, the results will be unnatural (digital), and values of more than 2 can compromise valuable detail because GIMP will then apply standard distributed noise to extend the effect.

Figure 4: "Unsharp Mask."

The Threshold value specifies the parts of the image to which GIMP should apply the filter. To allow this to happen, GIMP internally creates a unsharp copy of the image and compares it pixel by pixel with the original. If the difference between the pixels is greater than the Threshold value, GIMP triggers the filter and enhances the contrast between the neighboring pixels; otherwise, GIMP just leaves the pixel as is. A higher Threshold value limits the effect of the filter to just a few parts of the image with high contrast fluctuations, whereas a Threshold of 0 will sharpen the whole image - this typically causes more noise and artefacts in gradual transitions, such as sky or skin colors, in the original. Use the Amount value carefully; 1 corresponds to 100 percent overmodulation.

The graph in Figure 5 shows the red pixel line in Figure 2 before and after calling Unsharp Mask with two different parameter sets. The green graph represents the brightness of the original pixels. Using an Amount value of 65 percent causes the orange line with considerable overemphasis of the light-dark contrast at its edges (Figure 7). The red line overdoes the effect by using an Amount value of 150 percent leading to the oversharp image shown in Figure 6.

Figure 5: Green: Original, Orange: Unsharp Mask 3/0.65/2, Red: 3/1.5/2.

Figure 6: Overdone sharpness: Unsharp Mask with Radius 3, Amount 1.5, Threshold 2.

Figure 7: After applying an "Unsharp Mask" with a Radius value of 3, an Amount of 0.65, and a Threshold of 2, contrast is moderately improved.

Different motifs require different settings of Unsharp Mask. Photo expert Scott Kelby recommends editing portraits with Radius 1, Amount 1.5, and Threshold 10 [2]. The high Threshold value applies the filter to those areas that already have peak contrast changes. Silky smooth skin is not affected by this. In contrast to this, Kelby recommends R=3, A=0.65, T=2 for urban structures such as buildings. For all other subjects, the recommend values are R=1, A=0.85, T=4. Of course, these values are simply a starting point for your experiments, especially considering the fact that Kelby is actually referring to Photoshop rather than GIMP, and that perfect focus depends on your personal preferences. The Unsharp Mask function in GIMP's role model, Photoshop, tends to create similar results with the same values, as you can see in Figure 8. Photoshop CS3 also includes revolutionary new tools such as Smart Sharpen (with proprietary algorithms).

Figure 8: Photoshop does a similar job - an image sharpened using Photoshop's "Unsharp mask" with settings of Radius 3, Amount 65 percent, Threshold 2.

Selective Sharpening

If an image comprises sections with different degrees of focus, it doesn't normally make sense to sharpen the whole image, as the relatively high levels of enhancement needed to sharpen the fuzzy parts will lead to artefacts (halos) in parts that are already relatively sharp. GIMP has a selective sharpening tool for this; however, it is difficult to script because the user must specify what to sharpen to what extent before applying the function.

A filtering technique leads to automating the process: If you apply a high-pass to filter parts of the image with contrasting light-dark transitions, the subsequent Unsharp mask can concentrate on these parts of the image while leaving the rest of the image untouched. The GIMP script in the smartsharp Listing implements this do-it-yourself sharpening method. Line 18 creates a menu entry at the bottom of GIMP's Image dialog, which pops up when you right click an image (Figure 9).

Figure 9: The new "Smartsharp" menu item appears at the GIMP's Image context menu.

The exit main() instruction in Line 25 is required by the GIMP API. The smartsharp function in Line 28 does the real work, starting by acquiring a reference to the active layer of the image currently being edited in Line 34. Sharpening takes place in a copy of the layer, which the $sharp_layer variable holds a reference to. To allow this to happen, the layer_copy() method copies the active layer to a new one, which does not appear in the Layer dialog until image_add_layer() is called. The overlay mode for the new layer is set to OVERLAY_MODE in Line 58.

The plug_in_unsharp_mask function in Line 49 performs an unsharp mask transformation on the layer copy, titled sharp, using parameters of Radius 1, Amount 1.0, and Threshold 0 - that is, it affects the whole image. We are using a high pass filter to define where to apply the Unsharp Mask algorithm rather than relying on GIMP's own function. Line 59 creates the mask as a new, temporary layer, which is labeled mask in Line 63. The $mask_layer variable stores a pointer to it. Following this, the plug_in_neon method, an edge detector with a radius of 10 and an effect enhancement value of 0.1, filters those parts of the image with pronounced local light-dark fluctuations. The plug_in_gauss_irr() method, which is then called, applies Gaussian noise to extend the results of the filter and fuzzes the edges to avoid abrupt application of the mask later on (Figure 10).

Figure 10: A high pass filter detects edgy parts of an image, and a noise generator extends the identified areas and smoothes out the results. Later it is used as a Layer Mask.

Now Lines 75 through 86 simply need to apply the mask layer as the layer mask for the sharp layer to make sure that GIMP only sharpens where the mask contains true values. edit_paste() followed by floating_sel_anchor() does this trick. The mask layer at the top is no longer needed and is thus deleted in Line 89.

To merge the two remaining layers, the masked sharp layer and the original image, image_merge_down pushes the top layer into the bottom one. The result is the modified original layer. It is important for the smartsharp function, which we called via the GIMP menu, to return a reference to the manipulated image object; failure to do this will prompt a storm of protest from GIMP. The final result is the sharp image in Figure 11.

Figure 11: The results of our do-it-yourself sharpening tool: edgy areas of the image are in focus, and there are less artefacts on smooth surfaces.
Listing 1: smartsharp
01 #!/usr/bin/perl
02 use warnings;
03 use strict;
04
05 use Gimp qw(:auto);
06 use Gimp::Fu;
07 use Log::Log4perl qw(:easy);
08
09 register(
10   "perl_fu_smartsharp"
11   ,    # Name
12   "Sharpen an Image"
13   ,               # Explain
14   "It's easy!",   # Help
15   "Mike Schilli", # Author
16   "GPL",          # Copyright
17   "2009/06/30",   # Date
18   "<Image>/Smartsharp"
19   ,       # Menu
20   "*",    # Images accepted
21   [],
22   \&smartsharp    # Function
23 );
24
25 exit main();
26
27 #############################
28 sub smartsharp {
29 #############################
30   my ($img) = @_;
31
32   my $layer =
33     $img
34     ->image_get_active_layer(
35     );
36
37   # Create a copy to sharpen
38   my $sharp_layer =
39     $layer->layer_copy(0);
40   $sharp_layer
41     ->layer_set_mode(
42     OVERLAY_MODE);
43   $sharp_layer
44     ->drawable_set_name(
45     "sharp");
46   $img->image_add_layer(
47     $sharp_layer, -1 );
48
49   $img->plug_in_unsharp_mask(
50     $sharp_layer, 1, 1.0,
51     0 );
52
53   # Create a mask layer
54   my $mask_layer =
55     $layer->layer_copy(0);
56   $mask_layer
57     ->layer_set_mode(
58     OVERLAY_MODE);
59   $img->image_add_layer(
60     $mask_layer, -1 );
61   $mask_layer
62     ->drawable_set_name(
63     "mask");
64
65   # High Pass Filter,
66   # blur result
67   $img->plug_in_neon(
68     $mask_layer, 10.0, .1 );
69   $img->plug_in_gauss_iir(
70     $mask_layer, 20.0, 1,
71     1 );
72
73   # Add mask layer as mask
74   # to sharp layer
75   my $sharp_mask =
76     $sharp_layer
77     ->layer_create_mask(0);
78   $sharp_layer
79     ->layer_add_mask(
80     $sharp_mask);
81   $mask_layer->edit_copy();
82   my $float =
83     $sharp_mask->edit_paste(
84     0);
85   $float
86     ->floating_sel_anchor();
87
88   # Clean up
89   $img->image_remove_layer(
90     $mask_layer);
91   $img->image_merge_down(
92     $sharp_layer, 0 );
93   return $img;
94 }

Installation

To tell GIMP to parse the smartsharp script when it launches, you must install the script in GIMP's plugin directory with the following command line:

gimptool-2.0 --install-bin smartsharp

The gimptool-2.0 utility is provided by the Debian libgimp2.0-dev package. So that GIMP can understand Perl scripts, you also need to install libgimp2.0 and libgimp-perl.

Significant Order

If you are changing the image in any other way, resizing, or correcting the colors, make sure that sharpening is the last step you perform. Otherwise, the various methods could step on each other's toes and possibly even reverse the sharpening process.

Of course, if an image is badly out of focus, no kind of manipulation is going to make a mega-sharp masterpiece of it; techniques like the tricks I cover here in this article are just patchwork. Out-of-focus images contain less information than sharp images - removing information from an image is easy, but adding information is just about as difficult as getting toothpaste back into the tube.

INFO
[1] Listings: http://www.linux-magazine.com/Resources/Article-Code
[2] The Digital Photography Book by Scott Kelby: http://www.kelbytraining.com/books/