Softening, Blurring, Sharpening and Embossing images
Describes the fundamental concepts behind producing many of the standard image processing operations: softening, blurring, sharpening and embossing images.
Its surprisingly easy to create most of the common image processing effects. The only things you need to be able to do are:
The second part criteria is probably the key for VB programmers (VB's Point and PSet or the GDI API GetPixel and SetPixel work, but they really don't cut it for performance) but luckily there is a way to achieve this by using a marvellous series of hacks to give you high-performance access to bitmap data, described in the article True Colour DIBSections.
Once you've got your head around accessing the pixels, you can move onto the easy stuff: applying simple Image processing filters to the pixels. In all of the Image Processing operations described here, all you need to be able to do is to walk through all of the pixels in an image and then read its nearest neighbours. But enough of the preamble, let's get on with how you do it.
Blurring and Smoothing Filters
Blurring or smoothing filers are known as low-pass filters. (Incidentally, the same concept can be applied to audio files; a low-pass filter has the effect of removing the higher frequencies, to allow you to produce radio or telephone style effects). To implement this type of filter, you add a contribution from the neighbouring pixels and reduce the contribution from the pixel itself. Here is an example blurring filter:
To understand how this works in practice its easier to see what it does. So, say we had a red pixel (RGB 0,0,255) surrounded by blue pixels (RGB 255,0,0) in a bitmap:
The result for the centre pixel will be the sum of 1/9 of each of the pixel's values, i.e.
(255/9),0,8x(255/9) = (31.9, 0, 216.7)
This is a mostly blue purple colour, so the single red value has been blurred by its blue neighbours to a bluer shade.
Normally, rather than expressing the filter in terms of floating point values (i.e. 1/9), we use integers to express the filter values and then give the filter an integer weight. The integer matrix is used for multiplication and the final values are divided by the weight. So the 3x3 matrix above is written:
You can modify the filter to blur more by increasing the number of pixels that are sampled in the matrix (e.g. use a 5x5 or 7x7 matrix rather than a 3x3 one) and by increasing the contribution for the pixels surrounding the central one.
To decrease the blurring effect and get a softening effect, increase the weight of the contribution from the central pixel:
A sharpening filter, also called a high-pass filter, emphasizes discontinuities in the pixel values by subtracting a contribution from the surrounding pixels from an increased central pixels. This means that when the surrounding pixels are dark, the central pixel is increased in brightness which enhances the edges of an image. A typical sharpening filter looks like this:
An unsharp mask filter achieves a sharpening effect by subtracting a blurred version of an image from a multiple of the original. In my sample unsharpening is achieved by subtracting the image filtered using a 3x3 blur matrix from twice the original value.
Embossing is achieved by setting pixels black except where there is a change in intensity. Typical filter matrices for embossing look like this:
In the Image Processing sample, 127 is added to all the pixel values output from the embossing filter to colour the embossed image grey. This gives a better 3D visual embossing effect. The effect can be made more attractive by colourising the result afterwards.
Further edge detection filters can be implemented using Prewitt edge detection matrices. Examples of these are:
The standard image processing functions are really easy to implement, provided you have a way to get and set the pixels fast enough.