I am slowly developing a toolset for processing photographic images.
PhotoPnMTools now includes interactive editing of pictures and generation of Web albums.
Download Version 1.3
(Changes)
Download Version 1.2.1
Download Version 1.2 (patchlevel 2,fixed
rounding error problem)
Download Version 1.1
Download Version 1.0
To whet your appetite: some test images!
A better solution is to weigh the source pixels in the destination image according to their relative position to the four closest destination pixels. I first tried this algorithm to render fractals, with very good results. While the perceived sharpness may be less than without anti-aliasing (i.e. details have a somewhat soft contrast), this is misleading, as the method retains significantly more visually-useful detail than without anti-aliasing. The weights can be made non-linear, or one can use a sharpening filter, to compensate for the soft detail contrast.
Theoretically, an anti-aliased image does not contain more information than a non-anti-aliased one, but in practice, an anti-aliased image is visually more meaningful: the resulting image looks as if you were looking at it from such a distance that the details look blurred. There are some cases in which anti-aliasing shows very much improved results. For example, the effect of anti-aliasing really shows in fractals. I did a really wonderful fractal print by shrinking a large image, and sharpening it afterwards.
Sinc also has a disadvantage: it produces ripples, sometimes referred to as `ripple artifacts', even though they are not, strictly speaking, artifacts, but rather, the result of a wrong assumption. The assumption is that the original image of which the sampled image was taken does not contain signals of greater frequencies than could be recorded by the sampled image. While this assumption is not necessarily false, it usually is in practice. I did not find the ripples very obtrusive, though, and they do produce some extra sharpness to the image, which is what they are for. They are worst in line drawing type images, and least obtrusive in photographic images. When applying sharpening filters though, they may become obtrusive in some cases. For large magnifications, an advantage is that the pixels of the original image are minimally visible.
Y = R*0.211 + G*0.658 + B*0.131
Y is a dimension found in the colour space used by TVs, and may also be used to translate a colour image into a greyscale image, and produces about the right intensities for the different colours (for example, blue is darkest and yellow is lightest). Now, pnmhsy uses this weighted sum as its brightness parameter. The weights can be user-defined, but the defaults are those given above.
However, when we look at it more theoretically, there's a neater solution to the `darkening' problem. If we look again at our bright pink (r=255,g=200,b=200) we would expect an increase in saturation to lead to something like (r=350,g=150,b=150) or so, while in HSV we get (r=255,g=150,b=150), and in HLS the colour remains the same, as saturation cannot further be increased. In our HSY model, we do get something like (r=350,g=150,b=150). To ensure that we get legal rgb values again (r,g,b <= 255), HSY can use two ways: decrease brightness to make the rgb fit in (darkening), or add some white back to the colour to simulate a very bright colour (called whitening). We can darken manually by applying some darkening (-d), and whitening is done automatically (but can be turned off or decreased using -w).
If we look again at the HLS formula again from the perspective of whitening as a means to compress rgb values back to the legal range, we could say that whitening does about the same thing as HLS for bright colour, only it is theoretically sounder and (I think) it looks better. Actually, we could say that HLS assumes that bright colours (such as our bright pink) are actually colours which were originally very bright and saturated, and are represented in the image as whitened. But, we will never know if our bright pastel colours (such as our pink) are just that, or are actually overexposed areas which were whitened by the medium (actually film and digital cameras behave differently here, though both use a kind of whitening). Here, we assume for simplicity and mathematical neatness that colours are just what they are. However, we do have two different choices which are appropriate for these two different situations. If colours are just what they are, we can darken the image a little when we increase saturation, to obtain an accurate high-saturation image. If some colours represent over-exposed areas (such as the sun in a sunset) we don't use darkening, as it will make the over-exposed areas look greyish (a grey sun looks pretty unnatural).
One surprising thing I discovered was that the HLS model actually introduces serious noise into pictures. I first thought that this noise was just noise in the picture that is amplified, but as it turns out, it is noise resulting from the brightness problems with L. For some colours (such as cyan), small changes in H and S lead to great changes in brightness, even while L stays the same. When we saturate, noise enters in the picture. See the test page below.
Beside saturation and brightness, ppmhsy also turned out to be quite useful for changing colour balance and contrast in a natural way. I was in fact quite surprised by the wonderful results obtained by doing brightness-preserving colour balance using HSY, and doing contrast operations in HSY space. See the test page for results.
Illustration of some functions of ppmhsy
Saturation test images
Contrast test images
The standard convolution filter has a couple of weaknesses, which I tried to remedy using a couple of special parameters. One weakness is that noise is amplified, and we especially see `white noise' in plain areas. This problem can be solved by having pixels with low contrast weigh less (similar to the `unsharp mask' threshold parameter, only continuous). A second weakness is that borders with high contrast are too much intensified. This problem is solved by reducing large changes in intensity of pixels. The result is a filter that still looks good at high sharpening factors.
pnmconvolve also supports unsharp mask sharpening. To do this, one specifies a blur operation, and then uses the blurred result as the unsharp mask.
Boris van Schooten, boris@13thmonkey.org