× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

How to create and apply a Gaussian filter in MATLAB without using fspecial or imfilter

Ray Phan
Feb 02, 2015
<p>It's really unfortunate that you can't use the some of the built-in methods from the Image Processing Toolbox to help you do this task. However, we can still do what you're asking, though it will be a bit more difficult. I'm still going to use some functions from the IPT to help us do what you're asking. Also, I'm going to assume that your image is <strong>grayscale</strong>. I'll leave it to you if you want to do this for colour images.</p> <hr> <h1>Create Gaussian Mask</h1> <p>What you can do is create a grid of 2D spatial co-ordinates using <a href="http://www.mathworks.com/help/matlab/ref/meshgrid.html" rel="nofollow"><code>meshgrid</code></a> that is the same size as the Gaussian filter mask you are creating. I'm going to assume that <code>N</code> is odd to make my life easier. This will allow for the spatial co-ordinates to be symmetric all around the mask.</p> <p>If you recall, the 2D Gaussian can be defined as:</p> <p><img src="http://patentimages.storage.googleapis.com/WO2010053874A1/imgf000014_0001.png" alt="">. The scaling factor in front of the exponential is primarily concerned with ensuring that the area underneath the Gaussian is 1. We will deal with this normalization in another way, where we generate the Gaussian coefficients <strong>without</strong> the scaling factor, then simply sum up all of the coefficients in the mask and divide every element by this sum to ensure a unit area.</p> <p>Assuming that you want to create a <code>N x N</code> filter, and with a given standard deviation <code>sigma</code>, the code would look something like this, with <code>h</code> representing your Gaussian filter.</p> <pre><code>%// Generate horizontal and vertical co-ordinates, where %// the origin is in the middle ind = -floor(N/2) : floor(N/2); [X Y] = meshgrid(ind, ind); %// Create Gaussian Mask h = exp(-(X.^2 + Y.^2) / (2*sigma*sigma)); %// Normalize so that total area (sum of all weights) is 1 h = h / sum(h(:)); </code></pre> <p>If you check this with <code>fspecial</code>, for odd values of <code>N</code>, you'll see that the masks match.</p> <hr> <h1>Filter the image</h1> <p>The basics behind filtering an image is for each pixel in your input image, you take a pixel neighbourhood that surrounds this pixel that is the same size as your Gaussian mask. You perform an element-by-element multiplication with this pixel neighbourhood with the Gaussian mask and sum up all of the elements together. The resultant sum is what the output pixel would be at the corresponding spatial location in the output image. I'm going to use the <a href="http://www.mathworks.com/help/images/ref/im2col.html" rel="nofollow"><code>im2col</code></a> that will take pixel neighbourhoods and turn them into columns. <code>im2col</code> will take each of these columns and create a matrix where each column represents one pixel neighbourhood. </p> <p>What we can do next is take our Gaussian mask and <strong>convert</strong> this into a column vector. Next, we would take this column vector, and replicate this for as many columns as we have from the result of <code>im2col</code> to create... let's call this a Gaussian matrix for a lack of a better term. With this Gaussian matrix, we will do an element-by-element multiplication with this matrix and with the output of <code>im2col</code>. Once we do this, we can sum over all of the rows for each column. The best way to do this element-by-element multiplication is through <a href="http://www.mathworks.com/help/matlab/ref/bsxfun.html" rel="nofollow"><code>bsxfun</code></a>, and I'll show you how to use it soon.</p> <p>The result of this will be your filtered image, but it will be a single vector. You would need to reshape this vector back into matrix form with <a href="http://www.mathworks.com/help/images/ref/col2im.html" rel="nofollow"><code>col2im</code></a> to get our filtered image. However, a slight problem with this approach is that it doesn't filter pixels where the spatial mask extends beyond the dimensions of the image. As such, you'll actually need to pad the border of your image with zeroes so that we can properly do our filter. We can do this with <a href="http://www.mathworks.com/help/images/ref/padarray.html" rel="nofollow"><code>padarray</code></a>.</p> <p>Therefore, our code will look something like this, going with your variables you have defined above:</p> <pre><code>N = 5; %// Define size of Gaussian mask sigma = 2; %// Define sigma here %// Generate Gaussian mask ind = -floor(N/2) : floor(N/2); [X Y] = meshgrid(ind, ind); h = exp(-(X.^2 + Y.^2) / (2*sigma*sigma)); h = h / sum(h(:)); %// Convert filter into a column vector h = h(:); %// Filter our image I = imread(image); I = im2double(I); I_pad = padarray(I, [floor(N/2) floor(N/2)]); C = im2col(I_pad, [N N], 'sliding'); C_filter = sum(bsxfun(@times, C, h), 1); out = col2im(C_filter, [N N], size(I_pad), 'sliding'); </code></pre> <hr> <p><code>out</code> contains the filtered image after applying a Gaussian filtering mask to your input image <code>I</code>. As an example, let's say <code>N = 9, sigma = 4</code>. Let's also use <code>cameraman.tif</code> that is an image that's part of the MATLAB system path. By using the above parameters, as well as the image, this is the input and output image we get:</p> <p><img src="http://i.stack.imgur.com/8UxH8.png" alt="enter image description here"></p> <p><img src="http://i.stack.imgur.com/q9SSV.png" alt="enter image description here"></p> <p>This tip was originally posted on <a href="http://stackoverflow.com/questions/27499057/How%20to%20create%20and%20apply%20a%20Gaussian%20filter%20in%20MATLAB%20without%20using%20fspecial%20or%20imfilter/27500953">Stack Overflow</a>.</p>
comments powered by Disqus