I've been playing around with image processing lately, and I'd like to know how the unsharp mask algorithm works. I'm looking at the source code for Gimp and it's implementation, but so far I'm still in the dark about how it actually works. I need to implement it for a project I'm working on, but I'd like to actually understand the algorithm I'm using.
The Sharpening Tool is like using a hammer to sharpen. There is no fine control. The Unsharp Mask Tool give fine control. It finds the edges of the different tones and increases contrast to make the image appear sharper.
The UnSharp Mask filter is absolutely wonderful indeed, certainly very worthwhile, and perhaps even required! But do experiment and pay attention to the results, and practice moderation. Unlike Setting the Black and White Points, it is not of any particular advantage to apply the USM sharpening during the scan.
I wasn't sure how it worked either but came across a couple of really good pages for understanding it. Basically it goes like this:
Finally put it all together. You have three things at this point:
The algorithm goes like this: Look at a pixel from the unsharp mask and find out its luminosity (brightness). If the luminosity is 100%, use the value from the high-contrast image for this pixel. If it is 0%, use the value from the original image for this pixel. If it's somewhere in-between, mix the two pixels' values using some weighting. Optionally, only change the value of the pixel if it changes by more than a certain amount (this is the Threshold slider on most USM dialogs).
Put it all together and you've got your image!
Here's some pseudocode:
color[][] usm(color[][] original, int radius, int amountPercent, int threshold) {
// copy original for our return value
color[][] retval = copy(original);
// create the blurred copy
color[][] blurred = gaussianBlur(original, radius);
// subtract blurred from original, pixel-by-pixel to make unsharp mask
color[][] unsharpMask = difference(original, blurred);
color[][] highContrast = increaseContrast(original, amountPercent);
// assuming row-major ordering
for(int row = 0; row < original.length; row++) {
for(int col = 0; col < original[row].length; col++) {
color origColor = original[row][col];
color contrastColor = highContrast[row][col];
color difference = contrastColor - origColor;
float percent = luminanceAsPercent(unsharpMask[row][col]);
color delta = difference * percent;
if(abs(delta) > threshold)
retval[row][col] += delta;
}
}
return retval;
}
Note: I'm no graphics expert, but this is what I was able to learn from the pages I found. Read them yourself and make sure you agree with my findings, but implementing the above should be simple enough, so give it a shot!
The key is the idea of spatial frequency. A Gaussian filter passes only low spatial frequencies, so if you do something like:
2*(original image) - (gaussian filtered image)
Then it's effect in the spacial frequency domain is:
(2 * all frequencies) - (low frequencies) = (2 * high frequencies) + (1 * low frequencies).
So, in effect, an 'unsharp mask', is boosting the high frequency components of the image --- the exact parameters of the gaussian filter size, and the weights when the images are subtracted determine the exact properties of the filter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With