Look at the image above. If you squint, you might be able to make out what it is. I made this image by importing a public domain image into MATLAB by typing “A = imread(“noise.png”); then typing “A=imnoise(uint8(A),’salt & pepper’,0.6);”
The end result is a scrambled image that really doesn’t convey any meaningful information. Salt and pepper style distortion is characterized by areas with random minimum and maximum value pixels. This will either be random white and black pixels in grayscale pictures or random red, green, or blue pixels in color images. This type of problem usually happens in digital systems where a digital “1” turns into a digital “0” (or the reverse!) by mistake.
Suppose we want to write a MATLAB script to denoise our image. This post isn’t about solving differential equations so we’ll leave that for another day.
Seen below is our Total Variation equation created by the mathematicians Rudin, Osher, and Fatemi.
This is a series of first and second derivatives that will calculate the Minimum of the Total Variation Energy. The 2/lambdaD(u-f) portion of the function acts as a fidelity factor to attempt to minimize “false positive” denoising which would erode the original image. D is a variable for a denoising mask that we’ll create by hand (well, kind of) before running our denoising function.
Let’s get started. This article assumes that you have MATLAB with the Image Processing Toolbox installed. If you’re a student, you can obtain an educational license with many of the most common toolboxes preloaded for $99 at the time of writing. If not, you could use this as an informational guide for writing your own algorithms in another language or try to use the Linux MATLAB-clone called “Octave.” I’m also assuming that you have some knowledge of how to operate MATLAB. If not, consider getting this book. It helped me figure out what I was doing for basic functions.
For this program, you’ll manually type in the D = lines that are in italics into the command line to set up your mask. You’ll then create a function named TV_inpaint with all of the code up to the “end function” comment. You’ll then run the function by typing the TV_inpaint command with the 3 required inputs into the command line. Good luck!
First, we will look at the code to create our denoising mask:
D = ones(size(A));
D = D – D.*(A==255 | A==0);
What this does is create a mask that detects only the Salt and Pepper noises in the image. It looks for either maximum or minimum values in the image then creates a binary mask from that.
If you look at the mask, it’ll just look like noise. That’s fine. Doing this will make our image look a lot better after we run our script. Speaking of which…
function [u] = TV_inpaint (f, lambda, D)
% Calculate TV energy value of an image.
% Input: Grayscale image f
% Output: TV Energy of image f
set(gcf,’color’,’white’); % white background
f = double(f);
This converts our input into double notation. We’ll convert it back to 8 bit later.
dt = 0.5;
T = 300;
R = 255*rand(size(f));
f = D.*f + (1-D).*R;
u = f;
This is our constant declaration. dt acts as our time step. Setting this higher will make the function run faster but can lead to instability. T is our maximum time to run. You can set it as high as you want and just exit out of the MATLAB script with CTRL+C. R is a randomization factor that will make our mask more effective. We’ll apply it to our input image f then set our image that’ll be evolved, u, equal to f.
for t = 0:dt:T
[m,n] = size(f);
% First derivatives
f_x = ( u(:,[2:n,n]) – u(:,[1,1:n-1]) ) / 2;
f_y = ( u([2:m,m],:) – u([1:m-1,1],:) ) / 2;
% Second derivative in x: f_xx
f_xx = u(:,[2:n,n]) – 2*u + u(:,[1,1:n-1]);
% Second derivative in y: f_yy
f_yy = u([2:m,m],:) – 2*u + u([1,1:m-1],:);
% Diagonal derivative f_xy
f_xy = (u([2:m,m],[2:n,n]) + u([1,1:m-1],[1,1:n-1])- u([1,1:m-1],[2:n,n])- u([2:m,m],[1,1:n-1])) / 4;
% Gives TV
u = u + dt.*((f_xx.*f_y.^2 – 2*f_x.*f_y.*f_xy + f_yy.*f_x.^2)./((f_x.^2 +f_y.^2).^(3/2)+0.1) – 2*lambda.*D.*(u-f));
imshow(uint8(u)); title(t);
drawnow;
end % end for
end % end function
This huge for-loop calculates the first and second derivative of our modified input image, f. It then applies the Total Variation denoising equation to our output image, u. We loop back up and do it all over again… hundreds and hundreds of times. I’ve written this script to do 3000 iterations. This will take a while to run but will produce a good output.
Alright, now that we’ve written everything, let’s run our script:
TV_inpaint(A,0.2,D);
This will input A as our image under test, D as our denoising mask, and applies a Lambda factor of 0.2.
For this post, I ran this script on the image at the top and received this as my output. I think it looks pretty good, considering the source image.