Smoothing an image was pretty intuitive. When we are smoothing an image we are actually trying to suppress details in the image. When we sharpen an image we are trying to do the opposite. So, how do we do that?
Rates of Change
When we are sharpening an image we are trying to enhance the differences. What are the differences? Well, let’s take a look at a 1D strip of intensities:
If we take a cursory look at these pixels we’ll see that the intensities gradually decrease from left to right before jumping back up dramatically then dropping back down. The dramatic ‘jumps’ are what will ultimately be enhanced when we sharpen the image. Here they are highlighted.
We want to know how fast the intensities are changing. If ∆ represents the rate of change between adjacent pixels then our rate of change looks like:
We just subtract the value of the next pixel from the value of the current pixel. A little more formally, this looks like
∆(x) = f(x+1) – f(x)
Under normal conditions, some natural variation will occur pixel by pixel. We want to ignore that natural variation and only concern ourselves when the change is drastic. For that we will have to perform the subtraction one more time.
Now we can see how fast each intensity is changing. Once again, let’s formalize this.
∆2(x) =∆(x+1) – ∆(x)
∆2(x) = (f(x+1) – f(x)) – (f(x) – f(x-1)
∆2(x) = f(x-1) – 2 * f(x) + f(x+1)
Implementing the 1D Case
Then the filter for our 1D case looks like
If we apply this to our image we end up with this from above:
If we subtract this from our original image something magical happens:
We have sharpened the image!
In order to achieve that result, we subtracted ∆2 from the original image f. Our new formula looks like:
sharp = f – ∆2
so in the x direction,
sharp(x) = f(x) – ∆2(x)
sharp(x) = f(x) – (f(x-1) – 2 * f(x) + f(x+1))
sharp(x) = f(x) + -f(x-1) + 2 * f(x) – f(x+1)
sharp(x) = –f(x-1) + 3*f(x) – f(x+1)
Hence, our final 1D filter:
Expanding to 2D
If all images were just a single strip of pixels we’d be done. Unfortunately they aren’t, but accounting this is a pretty simple adjustment. The first thing to notice is that the 1D case works in any direction. If we wanted to apply the filter vertically instead of horizontally it would look like this:
So, how do we expand this to two dimensions? It’s pretty easy, actually:
Now you have a sharpening filter that will work in two dimensions. If you want to include the diagonals, there is no reason you can’t. Using the exact same method the final sharpening filter becomes:
And we’re done!
With some luck, you will have a solid grasp of how the sharpening filter works. If you are interested in researching this topic more, we walked through creating the Laplacian operator. If you are comfortable with calculus, the difference functions we discussed were actually just the first derivative (∆) and the second derivative (∆2).
Having discussed the filter code at length, the code is not posted here. The code from previous lessons will work fantastically.
Up Next: Sobel Operators