averaging mask and laplacian mask in image processing - matlab

in a given application I apply an averaging mask to input images to reduce noise, and then a Laplacian mask to enhance small details. Anyone knows if I Would get the same results if I reverse the order of these operations in Matlab?

Convolving with a Laplacian kernel is similar to using second derivative information about the intensity changes. Since this derivative is sensitive to noise, we often smooth the image with a Gaussian before applying the Laplacian filter.
Here's a MATLAB example similar to what #belisarius posted:
f='http://upload.wikimedia.org/wikipedia/commons/f/f4/Noise_salt_and_pepper.png';
I = imread(f);
kAvg = fspecial('average',[5 5]);
kLap = fspecial('laplacian',0.2);
lapMask = #(I) imsubtract(I,imfilter(I,kLap));
subplot(131), imshow(I)
subplot(132), imshow( imfilter(lapMask(I),kAvg) )
subplot(133), imshow( lapMask(imfilter(I,kAvg)) )

Lets say you have two filters F1 and F2, and an image I. If you pass your image through the two filters, you would get a response that was defined as
X = ((I * F1) * F2)
Where here I am using * to represent convolution.
By the associative rule of convolution, this is the same as.
X = (I * (F1 * F2))
using commutativity, we can say that
X = (I * (F2 * F1)) = ((I * F2) * F1)
Of course, this is in the nice continuous domain of math, doing these things on a machine means there will be rounding errors and some data may be lost. You also should think about if your filters are FIR, otherwise the whole concept of thinking about digital filtering as convolution sorta starts to break down as your filter can't really behave the way you wanted it to.
EDIT
The discrete convolution is defined as
so adding zeros at the edges of you data doesn't change anything in a mathematical sense.
As some people have pointed out, you will get different answers numerically, but this is expected whenever we deal with computing actual data. These variations should be small and limited to the low energy components of the output of the convolution (i.e: the edges).
It is also important to consider how the convolution operation is working. Convolving two sets of data of length X and length Y will result in an answer that is X+Y-1 in length. There is some behind the scenes magic going on for programs like MATLAB and Mathematica to give you an answer that is of length X or Y.
So in regards to #belisarius' post, it would seem we are really saying the same thing.

Numerically the results are not the same, but the images look pretty similar.
Example in Mathematica:
Edit
As an answer to #thron comment in his answer about commutation of linear filters and padding, just consider the following operations.
While commutation of a Gaussian and Laplacian filter without padding is true:
list = {1, 3, 5, 7, 5, 3, 1};
gauss[x_] := GaussianFilter[ x, 1]
lapl[x_] := LaplacianFilter[x, 1]
Print[gauss[lapl[list]], lapl[gauss[list]]]
(*
->{5.15139,0.568439,-1.13688,-9.16589,-1.13688,0.568439,5.15139}
{5.15139,0.568439,-1.13688,-9.16589,-1.13688,0.568439,5.15139}
*)
Doing the same with padding, result in a difference at the edges:
gauss[x_] := GaussianFilter[ x, 1, Padding -> 1]
lapl[x_] := LaplacianFilter[x, 1, Padding -> 1]
Print[gauss[lapl[list]], lapl[gauss[list]]]
(*
->{4.68233,0.568439,-1.13688,-9.16589,-1.13688,0.568439,4.68233}
{4.58295,0.568439,-1.13688,-9.16589,-1.13688,0.568439,4.58295}
*)

Related

Downsampling in MATLAB - why scaling filter coefficients?

Trying to undertsand how MATLAB does resampling, looking at toolbox/signal/resample.m.
This is the part where low-pass FIR filter coefficients are calculated:
fc = 1/2/pqmax;
L = 2*N*pqmax + 1;
h = firls( L-1, [0 2*fc 2*fc 1], [1 1 0 0]).*kaiser(L,bta)' ;
h = p*h/sum(h);
(In this case pqmax and p both represent downsampling ratio.)
Not sure what is the purpose of last line where all filter coefficients are scaled by downsampling ratio over coeffs sum, p/sum(h)? Does anyone know the theory behind?
MATLAB firls
MATLAB kaiser
firls theory: Least Squared Error Design of FIR Filters
In most filters, you want the output magnitude to remain equal after filtering, not scaled up or down.
Mathematically this is generally properly done in the filter equation, but in discrete numbers this doesnt generally doesn't apply.
If you divide the filer by its sum, you make sure that for any input data p, the filter will always have a general scale factor of 1, as its normalized. For a p=ones(1:1000,1), if sum(h) is not 1, the result after filtering will be scaled, i.e. the values of p_filtered will not be 1.

Weird behavior when performing 2D convolution by the FFT

I am trying to construct the product of the FFT of a 2D box function and the FFT of a 2D Gaussian function. After, I find the inverse FFT and I am expecting a convolution of the two functions as a result. However, I am getting a weird one-sided result as seen below. The result appears on the bottom right of the subplot.
The Octave code I wrote to reproduce the above subplot as well as the calculations I performed to construct the convolution is shown below. Can anyone tell me what I'm doing wrong?
clear all;
clc;
close all;
% domain on each side is 0-9
L = 10;
% num subdivisions
N = 32;
delta=L/N;
sigma = 0.5;
% get the domain ready
[x,y] = meshgrid((0:N-1)*delta);
% since domain ranges from 0-(N-1) on both sdes
% we need to take the average
xAvg = sum(x(1, :))/length(x(1,:));
yAvg = sum(y(:, 1))/length(x(:,1));
% gaussian
gssn = exp(- ((x - xAvg) .^ 2 + (y - yAvg) .^ 2) ./ (2*sigma^2));
function ret = boxImpulse(a,b)
n = 32;
L=10;
delta = L/n;
nL = ((n-1)/2-3)*delta;
nU = ((n-1)/2+3)*delta;
if ((a >= nL) && (a <= nU) && ( b >= nL) && (b <= nU) )
ret=1;
else
ret=0;
end
ret;
endfunction
boxResponse = arrayfun(#boxImpulse, x, y);
subplot(2,2,1);mesh(x,y,gssn); title("gaussian fun");
subplot(2,2,2);mesh(x,y, abs(fft2(gssn)) .^2); title("fft of gaussian");
subplot(2,2,3);mesh(x,y,boxResponse); title("box fun");
inv_of_product_of_ffts = abs(ifft2(fft2(boxResponse) * fft2(gssn))) .^2 ;
subplot(2,2,4);mesh(x,y,inv_of_product_of_ffts); title("inv of product of fft");
Let's first address your most obvious errors. This is the way you are computing the convolution in frequency domain:
inv_of_product_of_ffts = abs(ifft2(fft2(boxResponse) * fft2(gssn))) .^2 ;
The first problem is that you are using *, which is matrix multiplication. In frequency domain, element-wise multiplication is the equivalent to convolution in the frequency domain, so you need to use .* instead. The second problem is you also don't need the .^2 term and the abs operation. You're performing convolution, then finding the absolute value and squaring each term. This isn't required. Remove the abs and .^2 operations.
Therefore, what you need is:
inv_of_product_of_ffts = ifft2(fft2(boxResponse).*fft2(gssn)));
However, what you're going to get is this result. Let's place this in a new figure instead of a subplot*:
figure;
mesh(x,y,ifft2(fft2(boxResponse).*fft2(gssn)));
title('Convolution... not right though');
You can see that it's the right result... but it's not centred.... why is that?
This is actually one of the most common problems when computing convolution in the frequency domain. In fact, even the most experienced encounter this problem because they don't understand the internals of how the FFT works.
This is a consequence with how MATLAB and Octave compute the 2D FFT. Specifically, MATLAB and Octave defines a meshgrid of coordinates that go from 0,1,...M-1 for the horizontal and 0,1,...N-1 for the vertical, giving us a M x N result. This means that the origin / DC component is at the top-left corner of the matrix, not the centre as we usually define things. Specifically, the traditional 2D FFT defines the coordinates from -(M-1)/2, ..., (M-1)/2 for the horizontal and -(N-1)/2, ..., (N-1)/2 for the vertical.
Referencing the aforementioned, you defined your signal with the centre assuming that it's the origin and not the top-left corner. To compensate for this, you need to add an fftshift (MATLAB doc, Octave doc) so that the output of the FFT is now centred at the origin and not the top-left corner to bring things back to the way they were, and therefore you really need:
figure;
mesh(x,y,fftshift(ifft2(fft2(boxResponse).*fft2(gssn))));
title('Convolution... now it is right');
If you want to double check that we have the right result, you can perform direct convolution in the spatial domain and we can compare the results between the method in frequency domain.
This is how you'd compute the result directly in spatial domain:
figure;
mesh(x,y,conv2(gssn,boxResponse,'same'));
title('Convolution... spatial domain');
conv2 (MATLAB doc, Octave doc) performs 2D convolution between two signals, and the 'same' flag ensures that the output size is the largest of the two signals, which is either the Gaussian or Box filter. You'll see that it's the same curve, and I won't show it here for brevity.
However, we can compare both of the results and see if they're the same element-wise. A method to do this would be to determine if subtracting each element in the result is less than some threshold... say.. 1e-10:
>> out1 = conv2(boxResponse, gssn, 'same');
>> out2 = fftshift(ifft2(fft2(boxResponse).*fft2(gssn)));
>> all(abs(out1(:)-out2(:)) < 1e-10)
ans =
1
This means that indeed both of these are the same.
Hope that makes sense! Remember, since you're defining your signal where the origin is at the centre, once you find the inverse FFT, you must shift things back so that the origin is now at the centre, not the top-left corner.
*: Minor note - All plots produced in this answer were generated with MATLAB R2015a. However, the code fully works in Octave - tested with Octave 4.0.0.

Derivative of Gaussian filter in Matlab

Is there a derivative of Gaussian filter function in Matlab? Would it be proper to convolve the Gaussian filter with [1 0 -1] to obtain the result?
As far as I know there is no built in derivative of Gaussian filter. You can very easily create one for yourself as follow:
For 2D
G1=fspecial('gauss',[round(k*sigma), round(k*sigma)], sigma);
[Gx,Gy] = gradient(G1);
[Gxx,Gxy] = gradient(Gx);
[Gyx,Gyy] = gradient(Gy);
Where k determine the size of it (depends to which extent you want support).
For 1D is the same, but you don't have two gradient directions, just one. Also you would create the gaussian filter in another way and I assume you already have your preferred method.
Here I gave you up to second order, but you can see the pattern here to proceed to further orders.
The convolving filter you posted ( [1 0 -1] ) looks like finite difference. Although yours I believe is conceptually right, the most correct and common way to do it is with [1 -1] or [-1 1], with that 0 in the middle you skip the central sample in approximating the derivative. This may work as well (but bare in mind that is an approximation that for higher orders diverge from true result), but I usually prefer the method I posted above.
Note: If you are indeed interested in 2D filters, Derivative of Gaussian family has the steerability property, meaning that you can easily create a filter for a Derivative of Gaussian in any direction from the one I gave you up. Supposing the direction you want is defined as
cos(theta), sin(theta)
Then the derivative of Gaussian in that direction is
Gtheta = cos(theta)*Gx + sin(theta)*Gy
If you reapply this recursively you can go to any order you like.
Of just use the derivative of a gaussian which is not more difficult then computing the gaussian itself.
G(x,y) = exp(-(x^2+y^2)/(2*s^2))
d/dx G(x, y) = -x/s^2 G(x,y)
d/dy G(x, y) = -y/s^2 G(x,y)
function [ y ] = dgaus( x,n )
%DGAUS nth derivative of exp(-x.^2)
odd=0*x;
even=exp(-x.^2);
for order=0:(floor(n/2)-1)
odd=-4*order*odd-2*x.*even;
even=-(4*order+2)*even-2*x.*odd;
end
if mod(n,2)==0
y=even;
else
y=-2*(n-1)*odd-2*x.*even;
end
end

How does the sgolay function work in Matlab R2013a?

I have a question about the sgolay function in Matlab R2013a. My database has 165 spectra with 2884 variables and I would like to take the first and second derivatives of them. How might I define the inputs K and F to sgolay?
Below is an example:
sgolay is used to smooth a noisy sinusoid and compare the resulting first and second derivatives to the first and second derivatives computed using diff. Notice how using diff amplifies the noise and generates useless results.
K = 4; % Order of polynomial fit
F = 21; % Window length
[b,g] = sgolay(K,F); % Calculate S-G coefficients
dx = .2;
xLim = 200;
x = 0:dx:xLim-1;
y = 5*sin(0.4*pi*x)+randn(size(x)); % Sinusoid with noise
HalfWin = ((F+1)/2) -1;
for n = (F+1)/2:996-(F+1)/2,
% Zero-th derivative (smoothing only)
SG0(n) = dot(g(:,1), y(n - HalfWin: n + HalfWin));
% 1st differential
SG1(n) = dot(g(:,2), y(n - HalfWin: n + HalfWin));
% 2nd differential
SG2(n) = 2*dot(g(:,3)', y(n - HalfWin: n + HalfWin))';
end
SG1 = SG1/dx; % Turn differential into derivative
SG2 = SG2/(dx*dx); % and into 2nd derivative
% Scale the "diff" results
DiffD1 = (diff(y(1:length(SG0)+1)))/ dx;
DiffD2 = (diff(diff(y(1:length(SG0)+2)))) / (dx*dx);
subplot(3,1,1);
plot([y(1:length(SG0))', SG0'])
legend('Noisy Sinusoid','S-G Smoothed sinusoid')
subplot(3, 1, 2);
plot([DiffD1',SG1'])
legend('Diff-generated 1st-derivative', 'S-G Smoothed 1st-derivative')
subplot(3, 1, 3);
plot([DiffD2',SG2'])
legend('Diff-generated 2nd-derivative', 'S-G Smoothed 2nd-derivative')
Taking derivatives in an inherently noisy process. Thus, if you already have some noise in your data, indeed, it will be magnified as you take higher order derivatives. Savitzky-Golay is a very useful way of combining smoothing and differentiation into one operation. It's a general method and it computes derivatives to an arbitrary order. There are trade-offs, though. Other special methods exist for data with a certain structure.
In terms of your application, I don't have any concrete answers. Much depends on the nature of the data (sampling rate, noise ratio, etc.). If you use too much smoothing, you'll smear your data or produce aliasing. Same thing if you over-fit the data by using high order polynomial coefficients, K. In your demo code you should also plot the analytical derivatives of the sin function. Then play with different amounts of input noise and smoothing filters. Such a tool with known exact answers may be helpful if you can approximate aspects of your real data. In practice, I try to use as little smoothing as possible in order to produce derivatives that aren't too noisy. Often this means a third-order polynomial (K = 3) and a window size, F, as small as possible.
So yes, many suggest that you use your eyes to tune these parameters. However, there has also been some very recent research on choosing the coefficients automatically: On the Selection of Optimum Savitzky-Golay Filters (2013). There are also alternatives to Savitzky-Golay, e.g., this paper based on regularization, but you may need to implement them yourself in Matlab.
By the way, a while back I wrote a little replacement for sgolay. Like you, I only needed the second output, the differentiation filters, G, so that's all it calculates. This function is also faster (by about 2–4 times):
function G=sgolayfilt(k,f)
%SGOLAYFILT Savitzky-Golay differentiation filters
s = vander(0.5*(1-f):0.5*(f-1));
S = s(:,f:-1:f-k);
[~,R] = qr(S,0);
G = S/R/R';
A full version of this function with input validation is available on my GitHub.

FFT MATLAB code correct?

I'd like to generate the frequency spectrum of seven concatenated cosine functions.
I am unsure whether my code is correct; in particular, whether N = time*freq*7 is correct, or whether it should be N = time*freq (without the times seven).
My code is as follow:
sn = [1, 2, 3, 4, 5, 6, 7, 8];
time = 1;
freq = 22050;
N = time*freq*7;
dt = 1/freq;
t = 0 : dt : time - dt;
y = #(sn, phasePosNeg) cos(2*pi*(1200-100*sn) * t + phasePosNeg * sn*pi/10);
f = [y(sn(1), 1), y(sn(2), -1), y(sn(3), 1), y(sn(4), -1), y(sn(5), 1), y(sn(6), -1), y(sn(7), 1)];
F = abs(fftshift(fft(f)))/N;
df = freq/N;
faxis = -freq/2 : df : (freq/2-1/freq);
plot(faxis, F);
grid on;
axis([-1500, 1500, 0, 0.6]);
title('Frequency Spectrum Of Concatenated Cosine Functions');
xlabel('Frequency (Hz)');
ylabel('Magnitude');
I suppose the essense of my question is:
Should the height of the spikes equal 1/7 of 0.5, or simply 0.5? (All cosine functions have an amplitude of 1.)
Thank you.
Let me correct/help you on a few things:
1) the fourier transform is typically displayed in dB for its magnitute. 20*log base10(FFT coeff)
2) there is no need to divide your FFT amplitudes by any value of N.
F = abs(fftshift(fft(f)))/N; %get rid of the N or N =1
3) if N is the number of points in your FFT N = size(t); because you've taken that many samples of the sin/cos functions
4) When plotting the function remember that the FFT spans from -Pi to + Pi and you need to remap it to the frequency spectrum using your sampling frequency
5) becasue of the large phase discontinuties between these functions, dont expect the forrier transform the be a bunch of large narrow peaks. (otherwise Phase Modulation would be the modulationscheme of choice... zero bandwidth)
This is clearly homework, so I'm just going to give some direction: In the concatenated case, think of it as though you're adding six waveforms, which are each padded by zeros (6x the length of the waveform), and then offset these so they don't overlap and then added together to form the concatenated waveform. In the case where you're adding the FFTs of the individual waveforms, also remember that you're assuming that they are periodic. So you basically need to handle the zero padding so that you're comparing apples to apples. One check, of course, is to just use one waveform throughout and make sure it works in this case (and this should return exactly the same result since the FFT assumes that waveform is periodic -- that is, infinitely concatenated to itself).
Thinking of this in terms of Parseval's Theorem will probably be helpful in figuring out how to interpret and normalize things.
It is correct to use N=(7*time)*freq, since your actual time of the waveform is 7*time, regardless of how you constructed it.
Several of the comments talk about discontinuities, but it should be noted that these usually exist in the FFT anyway, since the FFT waveform is assumed to be periodic, and that usually means that there are effectively discontinuities at the boundaries even in the non-concatenated case.