I'm having trouble applying a Gaussian filter to an Image and one of the requirements is to make sure it's a circularly symmetric filter. I am not sure if I need to add a zero-padding sequence but please take a look at my code below and let me know if you can help me out at all! Thank you!
Please Note: I am not able to use any toolbox functions otherwise this would be pretty simple and straightforward.
L=256;
L1 = 255;
%load 'iptest_im.mat'
%ipFreq(iptest01)
[ImageX,ImageY] = size(A);
load 'iptest_im.mat';
A = iptest01;
A=double(A); % Just in Case
Fourier=fft2(A);
ABS_Fourier=abs(Fourier);
%Gaussian
Gaussian=zeros(ImageX,ImageY);
sigma=5; % Sigma Values for Gaussian Filter **** WHERE YOU CHANGE
for i = 1:ImageX
for j = 1:ImageY
D = (i-ImageX/2)^2 + (j-ImageY/2)^2;
Gaussian(i,j) = L1*exp(-(D)/(2*(sigma)^2));
end
end
GaussianFilt = fft2(Gaussian);
FourierFilt = Fourier .* GaussianFilt;
%Display for No shift
FFT_NoShift = abs((log10(FourierFilt+1)));
minA=min(min(FFT_NoShift));
FFT_NoShift = FFT_NoShift-minA; % shift
maxA = max(max(FFT_NoShift));
if maxA~=0
FFT_NoShift=FFT_NoShift*L1/maxA; % compress or expand
end
%Display for Shift
FFT_Shifted = fftshift(abs(log10(FourierFilt+1)));
minA=min(min(FFT_Shifted));
FFT_Shifted = FFT_Shifted-minA; % shift
maxA = max(max(FFT_Shifted));
if maxA~=0
FFT_Shifted=FFT_Shifted*L1/maxA; % compress or expand
end
InvFFT = abs(ifft2(FourierFilt));
%InvFFT = abs(ifft2(FFT_Shifted1));
%InvFFT = abs(ifft2(FFT_NoShift1));
Normalizing Fourier Transform of Gaussian Filter to 1 Before Multiplying Spectral Components
Normalizing the Gaussian kernel before multiplying the frequency components will help with appropriate scaling. Here I used the maximum of the Gaussian kernel to normalizes all its components to 1. You could also apply fftshift() to all Fourier frequency components if wanted but the same result is achieved. Either shift all spectral components or shift none. You could probably apply some of that logarithmic scaling you have but I'm not totally sure of the implementation details surrounding that.
Greyscale_Image = rgb2gray(imread("peppers.png"));
[ImageX,ImageY] = size(Greyscale_Image);
Fourier_Transform = fft2(Greyscale_Image);
Gaussian = zeros(ImageX, ImageY);
sigma = 5;
for i = 1: ImageX
for j = 1:ImageY
D = (i-ImageX/2)^2 + (j-ImageY/2)^2;
Gaussian(i,j) = exp(-(D)/(2*(sigma)^2));
end
end
GaussianFilt = round(abs(fft2(Gaussian)));
%Normalizes the Guassian filter%
GaussianFilt = GaussianFilt./max(GaussianFilt,[],'all');
Reconstructed = uint8(ifft2(Fourier_Transform.*GaussianFilt));
imshow(Reconstructed);
Ran using MATLAB R2019b
I am plotting 2 multivariate gaussians in MATLAB, and my decision line as a result will be parabolic in shape, which I can see by looking at the contour or surf of the data. However, I need a way to quantify the pparabola that represents the decisionline. Taking the local minima seems like a good idea, but I dont know if that is possible for a contour plot.
decision line is where difference of two gaussian function becomes zero.
so using fcontour from symbolic toolbox:
syms x y
mu_x = 10;
mu_y = 10;
mu_x1 = 60;
mu_y1 = 10;
sigma = 20;
sigma1 = 30;
f = 1/(2*pi*sigma^2) * exp(-(x-mu_x)^2+(y-mu_y)^2)/(2*sigma^2)...
-( 1/(2*pi*sigma1^2) * exp(-(x-mu_x1)^2+(y-mu_y1)^2)/(2*sigma1^2));
fcontour(f ,'LevelList', [0])
but I do not have tested
I'm attempting to use scale space implementation to fit n Gaussian curves to peaks in a noisy time series digital signal (measuring voltage).
To test it I created the following sample sum of three gaussians with noise (0.2*rand, sorry no picture, i'm new here)
amp = [2; 0.9; 1.3];
mu = [19; 23; 28];
sigma = [4.8; 1.3; 2.5];
x = linspace(1,50,1000);
for n=1:3, y(n,:) = A(n)*exp(-(x-B(n)).^2./(2*C(n)^2)); end
noisysignal = y(1,:) + y(2,:) + y(3,:) + 0.2*rand(1,numel(x))
I found this article http://www.engineering.wright.edu/~agoshtas/GMIP94.pdf posted by user355856 answer to thread "Peak decomposition"!
I believe my code generates the correct result for plotting the zero crossings as a function of the gaussian filter resolution sigma, but I have two issues. The first is that it seems yet another fitting routine would be needed to identify the approximate location of the arch intercepts for approximating the initial peak sigma and mu values. The second is that the edges of the scale space plot have substantial arches that definitely do not correspond to any peak. I'm not sure how to screen these out effectively. Last thing is that is used a spacing of 50 when calculating the second derivative central finite difference since too much more destroyed feature, and to much less results in a forest of zero crossings. Would there be a better way to filter that to control random zero crossings in the gaussian peak tails?
function [crossing] = scalespace(x, y, sigmalimit)
figure; hold on; ylim([0 sigmalimit]);
for sigma = 1:sigmalimit %
yconv = convkernel(sigma, y); %convolve with kernel
xconv = linspace(x(1), x(end), length(yconv));
yconvpp = d2centralfinite(xconv, yconv, 50); % 50 was empirically chosen
num = 0;
for i = 1 : length(yconvpp)-1
if sign(yconvpp(i)) ~= sign(yconvpp(i+1))
crossing(sigma, num+1) = xconv(i);
num = num+1;
end
end
plot(crossing(sigma, crossing(sigma, :) ~= 0),...
sigma*ones(1, numel(crossing(sigma, crossing(sigma, :) ~= 0))), '.');
end
function [yconv] = convkernel(sigma, y)
t = sigma^2;
C = 3; % for kernel truncation
M = C*round(sqrt(t))+1;
window = (-M) : (+M);
G = zeros(1, length(window));
G(:) = (1/(2*pi()*t))*exp(-(window.^2)./(2*t));
yconv = conv(G, y);
This is my first post and I apologize in advance for any issues in style. I'm fairly new to programming, so any advice regarding the programming style or information provided in this question would be much appreciated. I also read through Amro's answer about matlab's GMM function! if anyone feels that would be a more efficient approach to modeling multiple gaussians in a digital signal.
Thank you!
I have a data distributed in non-equidistant 1D space and I need to convolve this with a Gaussian filter,
gaussFilter = sqrt(6.0/pi*delta**2)*exp(-6.0*x**2 /delta**2);
where delta is a constant and x corresponds to space.
Can anyone hint how to perform a good integration (2nd order) as the data is not equally spaced taking care of the finite end? I intend to write the code in Fortran, but a Matlab example is also welcome.
use this:
function yy = smooth1D(x,y,delta)
n = length(y);
yy = zeros(n,1);
for i=1:n;
ker = sqrt(6.0/pi*delta^2)*exp(-6.0*(x-x(i)).^2 /delta^2);
%the gaussian should be normalized (don't forget dx), but if you don't want to lose (signal) energy, uncomment the next line
%ker = ker/sum(ker);
yy(i) = y'*ker;
end
end
Found something which works.
Though not sure if this is very accurate way as the integration (trapz) is of first order.
function [fbar] = gaussf(f,x,delta )
n = length(f);
fbar = zeros(n,1);
for i=1:n;
kernel = sqrt(6/(pi*delta^2))*exp(-6*((x - x(k))/delta).^2);
kernel = kernel/trapz(x,kernel);
fbar(i) = trapz(x,f.*kernel);
end
end
I recently tried to implement on matlab a simple example of interpolation method using zéro padding in the fourier domain.
But I am not able to get this work properly, I always have a small frequency shift, barely not visible in fourier space, but thay generates a huge error in time space.
As zéro padding in the fourier space seems to be a common (and fast) interpolation method, I assume that there is something I am missing:
Here is the matlab code:
clc;
clear all;
close all;
Fe = 3250;
Te = 1/Fe;
Nech = 100;
F1 = 500;
F2 = 1000;
FMax = 1500;
time = [0:Te:(Nech-1)*Te];
timeDiscrete = [1:1:Nech];
frequency = (timeDiscrete/Nech)*Fe;
signal = cos(2*pi*F1*(time))+cos(2*pi*F2*(time))+cos(2*pi*FMax*(time));
%Compute the FFT
spectrum=zeros(1,Nech);
for k = timeDiscrete
for l = timeDiscrete
spectrum(k) = spectrum(k) + signal(l)*exp(-2*pi*j*l*k/Nech);
end
end
%Compute de inverse FFT
reconstruction=zeros(1,Nech);
for k = timeDiscrete
for l = timeDiscrete
reconstruction(k) = reconstruction(k) + spectrum(l)*exp(2*pi*j*l*k/Nech);
end
end
reconstruction=reconstruction/Nech;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%% Now interpolation will take place %%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Finterp = 6*Fe;
Tinterp = 1/Finterp;
TimeInterp = [0:Tinterp:(Nech-1)*Te];
[m,n] = size(TimeInterp);
NechInterp = n;
TimeInterpDiscrete = [1:1:NechInterp];
%Compute original signal value without any interpolation
signalResampled = cos(2*pi*F1*(TimeInterp))+cos(2*pi*F2*(TimeInterp))+cos(2*pi*FMax*(TimeInterp));
%Compute original signal interpolation by padding the fft and performing
%inverse fft on the result
semipaddedsize=floor(NechInterp/2);
padded_spectrum0 = zeros(1,semipaddedsize);
padded_spectrum0 = padarray(spectrum(1:Nech/2),[0 semipaddedsize-(Nech/2)],0,'post');
padded_spectrum = zeros(1,NechInterp);
padded_spectrum(1:semipaddedsize) = padded_spectrum0;
padded_spectrum(semipaddedsize+1:NechInterp-1) = conj(fliplr(padded_spectrum0));
% padded_spectrum = padarray(spectrum,[0 NechInterp-Nech],0,'post');
padded_timeDiscrete = [1:1:NechInterp];
padded_reconstruction = zeros(1,NechInterp);
for k = padded_timeDiscrete
for l = padded_timeDiscrete
padded_reconstruction(k) = padded_reconstruction(k) + padded_spectrum(l)*exp(2*pi*j*l*k/NechInterp);
end
end
padded_reconstruction=padded_reconstruction/(1*Nech);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%% Let's print out the result %%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
spectrumresampled=zeros(1,NechInterp);
for k = TimeInterpDiscrete
for l = TimeInterpDiscrete
spectrumresampled(k) = spectrumresampled(k) + signalResampled(l)*exp(-2*pi*j*l*k/NechInterp);
end
end
figure(2);
plot(abs(spectrumresampled)/6,'g');
hold on;
plot(abs(padded_spectrum),'b');
figure(3);
% Ground truth : deterministic signal is recomputed
plot(TimeInterp,signalResampled,'g');
hold on;
% linear interpolation between subsampled points (matlab tracing tool)
plot(time,(reconstruction),'c');
hold on;
% Padding the spectrum and reconstructing it
plot(TimeInterp,real(padded_reconstruction),'m');
hold on;
xlabel('Time in s','FontSize',16)
ylabel('Signal value (no unit)','FontSize',16)
title('\it{ Various signal reconstruction from fourier transform }','FontSize',16)
legend('True signal', 'Reconstruction with linear interpolation', 'Reconstruction with padded spectrum');
I am not able to post images of the result because of my reputation, but, graph are easy to generates, through matlab.
I would really appreciate a comment on either this code or zero padding fft for interpolation in general.
Thank you in advance
Thank you very much for both of you for those advices, I decided to respond my own question because the was not enough space available in coment box:
#Try hard I indeed defined a wrong discrete Time vector, as #Frederick also pointed out, I had a problem in padding my vector, thank you for giving me the right "matlab way" to do it, I should not have been so afraid of fftshift/ifftshift, in addition, the use of padarray with 'both' would also have done the job, as mentionned by #Frederick .
Collapsing the for loop was also an essential step for proper matlab implementation, that I don't use in training purpose to ease my understanding and bound checking.
An additionnal very interesting point #Try hard mentionned in its first sentence, and that I did not realised in the first place, is the fact, that zero padding is just the equivalent of convoluting my data in time domain by a sinc function.
Actually I think that it is literraly equivalent to a convolution with an aliased sinc function, also called dirichlet kernel, which limits, when sampling frequency increase towards infinity, is the classic sinc function (see http://www.dsprelated.com/dspbooks/sasp/Rectangular_Window_I.html#sec:rectwinintro)
I did not posted the whole code here, but the purpose of my original program was to compare dirichlet kernel convolution formula, that I demonstrated in a different framework (theoretical demonstration using fourier series discrete expression) , sinc convolution Whittaker–Shannon interpolation formula, and zero padding, so I should be given with a very similar result.
To the apodization question, I think that the true answer is that, if your signal is bandlimited, you don't need other apodization function than rectangular window.
If your signal is not bandlimited, or aliased regarding the sampling rate, you will need to reduce the contribution of aliased part of the spectrum, which is done by filtering them out with a frequency filter = apodizing window in frequency domain, wich turns into a specific interpolation kernels in time domain.
OK. One problem was the way you were doing the IDFT for padded_reconstruction. The way that you defined TimeInterp and thus NechInterp made the elements of the complex exponent incorrect. That accounts for the incorrect frequencies.
Then there was an issue with including the midpoint in the fourier domain (pt 50) twice. It was near zero, so it wasn't making a hugely obvious problem, but it should only be included once. I rewrote this section because I was having a hard time working it through exactly the way you did it. I kept it very close though. If I were doing this, I would use fftshift and then padarray(...,'both'), which would save the work of having to put the zeros in the middle. If you are doing this for a learning experience and trying not to use matlab tools (e.g. fftshift), then nevermind.
I also redid the way you define time, but to be fair, I think it could work your way.
I've indicated changes with %<<<<<<<<<<
Fe = 3250;
Te = 1/Fe;
Nech = 100;
F1 = 500;
F2 = 1000;
FMax = 1500;
time = [Te:Te:(Nech)*Te]; %<<<<<<<<<<
timeDiscrete = [1:1:Nech];
frequency = (timeDiscrete/Nech)*Fe;
signal = cos(2*pi*F1*(time))+cos(2*pi*F2*(time))+cos(2*pi*FMax*(time));
%Compute the FFT
spectrum=zeros(1,Nech);
for k = timeDiscrete
for l = timeDiscrete
spectrum(k) = spectrum(k) + signal(l)*exp(-2*pi*j*l*k/Nech);
end
end
%Compute de inverse FFT
reconstruction=zeros(1,Nech);
for k = timeDiscrete
for l = timeDiscrete
reconstruction(k) = reconstruction(k) + spectrum(l)*exp(2*pi*j*l*k/Nech);
end
end
reconstruction=reconstruction/Nech;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%% Now interpolation will take place %%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Finterp = 6*Fe;
Tinterp = 1/Finterp;
TimeInterp = [Tinterp:Tinterp:(Nech*6)*Tinterp]; %<<<<<<<<<<
[m,n] = size(TimeInterp);
NechInterp = n;
TimeInterpDiscrete = [1:1:NechInterp];
%Compute original signal value without any interpolation
signalResampled = cos(2*pi*F1*(TimeInterp))+cos(2*pi*F2*(TimeInterp))+cos(2*pi*FMax*(TimeInterp));
%Compute original signal interpolation by padding the fft and performing
%inverse fft on the result
padded_spectrum = zeros(1,NechInterp); %<<<<<<<<<<
padded_spectrum(1:floor(Nech/2-1)) = spectrum(1:floor(Nech/2-1)); %<<<<<<<<<<
padded_spectrum(end-floor(Nech/2)+1:end) = spectrum(floor(Nech/2)+1:end); %<<<<<<<<<<
padded_reconstruction = zeros(1,NechInterp);
for k = TimeInterpDiscrete %<<<<<<<<<<(no reason for new variable)
for l = TimeInterpDiscrete %<<<<<<<<<<(no reason for new variable)
padded_reconstruction(k) = padded_reconstruction(k) + padded_spectrum(l)*exp(2*pi*j*l*k/NechInterp);
end
end
padded_reconstruction=padded_reconstruction/(1*Nech);
The result you observe in the time domain is ringing due to convolution of a sinc function with your original data. This is the equivalent in the time domain of multiplication by a rectangular window in the frequency domain, which is in effect what you are doing when you zero fill. Don't forget to apodize!
I repost your code after collapsing the loops (which accelerates the computation significantly), redefining the ranges of the time and frequency variables (see the definition of DFT to see why), and removing one of the padding operations you perform which I frankly did not understand the point off.
clc;
clear all;
close all;
Fe = 3250;
Te = 1/Fe;
Nech = 100;
mlt = 10;
F1 = 50;
F2 = 100;
FMax = 150;
time = [0:Te:(Nech-1)*Te];
%timeDiscrete = [1:1:Nech];
timeDiscrete = [0:1:Nech-1];
frequency = (timeDiscrete/Nech)*Fe;
signal = cos(2*pi*F1*(time))+cos(2*pi*F2*(time))+cos(2*pi*FMax*(time));
spectrum = signal*exp(-2*pi*j*timeDiscrete'*timeDiscrete/Nech);
fspec = [0:Nech-1]*Fe/Nech;
reconstruction = spectrum*exp(2*pi*j*timeDiscrete'*timeDiscrete/Nech)/Nech;
figure
plot(time,signal)
hold on
plot(time,reconstruction,'g:')
% **** interpolation ****
Finterp = 6*Fe;
Tinterp = 1/Finterp;
TimeInterp = [0:Tinterp:(Nech-1)*Te];
NechInterp = length(TimeInterp);
%TimeInterpDiscrete = [1:NechInterp];
TimeInterpDiscrete = [0:NechInterp-1];
%Compute original signal value without any interpolation
signalResampled = cos(2*pi*F1*(TimeInterp))+cos(2*pi*F2*(TimeInterp))+cos(2*pi*FMax*(TimeInterp));
%Compute original signal interpolation by padding the fft and performing
%inverse fft on the result
padded_spectrum0 = spectrum;
padded_spectrum0(NechInterp) = 0;
fspecPadded = [0:NechInterp-1]*Finterp/NechInterp;
padded_reconstruction = padded_spectrum0*exp(2*pi*j*TimeInterpDiscrete'*TimeInterpDiscrete/NechInterp)/(1*Nech);
spectrumresampled = signalResampled*exp(-2*pi*j*TimeInterpDiscrete'*TimeInterpDiscrete/NechInterp);
fresampled = [0:NechInterp-1]*Fe/NechInterp;
% **** print out ****
figure(2);
hold on;
plot(fspec,abs(spectrum),'c');
plot(fresampled,abs(spectrumresampled)/6,'g--');
plot(fspecPadded,abs(padded_spectrum0),'m:');
xlabel('Frequency in Hz','FontSize',16)
ylabel('Signal value (no unit)','FontSize',16)
legend('True signal', 'Reconstruction with resampled spectrum', 'Padded spectrum');
figure(3);
% Ground truth : deterministic signal is recomputed
plot(TimeInterp,signalResampled,'g');
hold on;
% Padding the spectrum and reconstructing it
plot(TimeInterp,real(padded_reconstruction),'m:');
xlabel('Time in s','FontSize',16)
ylabel('Signal value (no unit)','FontSize',16)
title('\it{ Various signal reconstruction from fourier transform }','FontSize',16)
legend('True signal', 'Reconstruction with padded spectrum');
And here's an image of a horribly distorted signal due to padding in the frequency domain:
Some improvement is possible by first applying fftshift to center the spectrum and padding on alternate sides of the centered spectrum, then inverting the fftshift operation:
Nz = NechInterp-Nech;
padded_spectrum0 = ifftshift([ zeros(1,floor(Nz/2)) fftshift(spectrum) zeros(1,floor(Nz/2)+rem(Nz,2)) ]); % replaces (NechInterp) = 0;
fspecPadded = [0:NechInterp-1]*Finterp/NechInterp;
Then you arrive at this much nicer interpolated time domain signal because the padding operation does not result in such abrupt drop-offs in the spectrum (some improvements may still be possible however with further tinkering):