user defined gaussian kernel - matlab

I was wondering if anyone could look at this code. I'm trying to do a 3x3 gaussian kernel without using any matlab built-in functions. (Yes I am aware of all the built in functions of gaussian and convolution ie fspecial)
the result gives me a white image instead. not sure what's the problem with it.
clc;
close all;
clear all;
img=imread('image.jpg');
figure,imshow(img);
img2=zeros(size(img)+2);
newImg=zeros(size(img));
for rgb=1:3
for x=1:size(img,1)
for y=1:size(img,2)
img2(x+1,y+1,rgb)=img(x,y,rgb);
end
end
end
for i= 1:size(img2,1)-2
for j=1:size(img2,2)-2
window=zeros(9,1);
inc=1;
for x=1:3
for y=1:3
window(inc)=img2(i+x-1,j+y-1,rgb);
inc=inc+1;
end
end
kernel=[1;2;1;2;4;2;1;2;1];
% kernel=[0;1;0;1;-4;1;0;1;0];
med=window.*kernel;
disp(med);
med=sum(med);
med=floor(med);
newImg(i,j,:)=med;
end
end
newImg=uint8(newImg);
figure,imshow(newImg);
Thanks.

I guess you should normalize the kernel. I mean, devide each element by the sum of their value (16), to make their sum equal to 1:
kernel=[1;2;1;2;4;2;1;2;1]/16;

Related

error with 'parfor' in matlab

i have written a function in matlab, which is to calculate a cost function for an array:
function [F1val, Com]=F1(Community,NeighMat)
global FlattedAdjMat;
Com=zeros(numel(Community),3);
Com(:,1)=Community'; % The First row of Com= Community's Nodes
% Calculating INTERNAL Edges of Community
for j=1:numel(Com(:,1))
Com(j,2)=sum(FlattedAdjMat((Community),Com(j,1)));% Internal Degrees of Node j
end
F1val=(nansum(Com(:,3)./((Com(:,2)+Com(:,3)))));
end
But i have 2 problem with the line Com(j,2)=sum(FlattedAdjMat((Community),Com(j,1))),
when i try to execute it in parallel using parfor:
parfor iii=1:5
[z,p]=F1(Community,NeighMat)
end
this error occurs in the line: Index exceeds matrix dimensions
while in normal case(not Parallel) there is no problem
it is very time consuming and slow down the speed.
NeighMat is a weighted adjacency matrix,
Community is an array of the matrix indexes,
FlattedAdjMat is adjacency matrix.
whould you please help me?
sample data:
for ii=1:10
NeighMat{ii}=randi(10,1,10)
end
Community=[1,5,6,8,9];`
global FlattedAdjMat
FlattedAdjMat=randi([0,1],10,10)
You have a problem with global variable. This problem is well discussed here.
I rewrite Your code a bit and it works for me perfect (Matlab 2017b Win64)
close all
clear all
clc
%% SAMPLE DATA
for ii=1:10
NeighMat{ii}=randi(10,1,10);
end
Community=[1,5,6,8,9];
FlattedAdjMat=randi([0,1],10,10);
%% BODY
parfor iii=1:5
[z,p]=F1(Community,NeighMat,FlattedAdjMat)
end
%% FUNCTION
function [F1val, Com]=F1(Community,NeighMat,FlattedAdjMat)
Com=zeros(numel(Community),3);
Com(:,1)=Community'; % The First row of Com= Community's Nodes
% Calculating INTERNAL Edges of Community
for j=1:numel(Com(:,1))
Com(j,2)=sum(FlattedAdjMat((Community),Com(j,1)));% Internal Degrees of Node j
end
F1val=(nansum(Com(:,3)./((Com(:,2)+Com(:,3)))));
end

Placing gaussian function at different points on mesh

I am looking to create a random distribution of gaussian curve shapes on a large mesh. I basically want to take this function :
Z = 0.3*exp(-5*(x.^2+y.^2))-0.1;
Z(Z<0)=0;
and be able to choose its location (in x & y coords), and have multiple plots.
So at the moment, I have this:
But I would like to have this generated:
Is there a reasonably simple way to do this? I have tried to play around with the code but I am afraid I'm not a mathematics, nor a MATLAB expert.
Any help would be much appreciated.
Look at this!
the way this works:
Generate random point
Check if point is closer than sigma
If its not, then create a gaussian there!
repeat until Ngaussians reached
code:
clear
n_gaussians=15;
gaussians=0;
sigma=1; % std
mindist=sigma; % if distance is smaller than this gaussians "collide"
[x,y]= meshgrid(-5:0.1:5,-5:0.1:5);
used=[];
Z=zeros(size(x));
while gaussians<n_gaussians
xm=(rand(1)-0.5)*10;
ym=(rand(1)-0.5)*10;
notvalid=0;
for ii=1:size(used,2)
% if we are too close to any point.
if norm([xm-used(1,ii),ym-used(2,ii)])<mindist
notvalid=1; % do not add this gauusian
end
end
if notvalid
continue
end
used(:,end+1)=[xm;ym];
Zaux = 0.3/sigma*exp(-5*((x-xm).^2+(y-ym).^2)/sigma.^2)-0.1;
Zaux(Zaux<0)=0;
Z=Z+Zaux;
gaussians=gaussians+1;
end
surf(x,y,Z);
axis equal

Optimize computation time for PDF approximation based on Kernel Density Estimation

I have a code to find the pdf's approximation of a vector based on the formula for kernel estimation:
I implemented this formula in the code below (see previous question). However, that code takes long time to run (two loops are used). Could you see the below code and help me to make it faster?
This is the code:
function pdf_est=KDE()
close all;
%%Random values of 20 pixels, range=[1 256]
data=randi([1 256],1,20)-1; %// changed: "-1"
%% Estimate histogram%%%%%
pdf_est=zeros(1,256);
z=256;
for i=0:z-1 %// changed_ subtracted 1
for j=1:length(data)
pdf_est(i+1)=pdf_est(i+1)+Gaussian(i-data(j)); %// changed: "+1" (twice)
end
end
%% Plot real histogram 1 to 256; binsize=1;
hold on
plot(0:255, imhist(uint8(data))./length(data),'r'); %// changed: explicit x axis
%% Plot histogram estimation
plot(0:255, pdf_est./length(data),'b'); %// changed: explicit x axis
hold off
function K=Gaussian(x)
sigma=1; %// change? Set as desired
K=1./(sqrt(2*pi)*sigma)*exp(-x^2./(2*sigma^2));
You can get rid of both of those nasty nested loops and then use the hardcoded sigma to have a mega-reduced vectorized solution -
pdf_est = sum(1./(sqrt(2*pi))*exp(-bsxfun(#minus,[0:z-1]',data).^2/2),2)
Or if you would like to have the flexibility to have sigma around, use this -
sum(1./(sqrt(2*pi)*sigma)*exp(-bsxfun(#minus,[0:z-1]',data).^2/(2*sigma^2)),2)
That's all really there is!
Quick tests put this to speedup the original code by 10x!

Custom autocorrelation with overlapping sliding window

I am trying to make a custom autocorrelation function in matlab according to info in the image below:
the function works but i get an error that index exceeds matrix dimensions, mathematically it's wright but in programming am i missing something? Here is my code:
close all; clear all; clc;
[x,fs]=audioread('c1.wav');
N=length(x); %// length of signal
n1=128; %// length of window
win_num=floor(N/n1); %// number of windows
m=1:n1;
for l=1:n1/2:win_num %// 50% overlapping - 64 samples for a 128 window
for n=1:N-m
cmax(n)=max(sum(x(n+m)*conj(x(n))));
end
end
thanks in advance.
I am assuming that when you do for n=1:N-m you want to do for n=1:N-max(m) (or for n=N-m(end)).
If you do the first one N-m returns an array, not a single value, as m is an array!

STFT computation without using spectrogram function!

I was trying to plot STFT using plot3 in MATLAB but failed. Can somebody guide me how to do that? My MWE is given below:
%% STFT Computataion
clear; clc; clf;
%% Get input and calculate frame size and overlap/shift
[Y,Fs]=wavread('D_NEHU_F0001_MN_10001');
frame_size=round(20*Fs/1000); % calculate frame size for 20ms
frame_shift=round(10*Fs/1000); % calculate frame shift for 10ms
%% Plot the input signal in time domain
t=1/Fs:1/Fs:(length(Y)/Fs);
subplot(2,1,1)
plot(t,Y);
title('Speech signal in time domain');
ylabel('Magnitude of samples');
xlabel('time in seconds');
%% Calculation of STFT
%NoOfFrames=floor((length(Y)/frame_shift)-1);
NoOfFrames=length(Y)-frame_size;
j=1;
%for i=1:frame_shift:(length(Y)-frame_size)
for i=1:frame_shift:((length(Y)-frame_size))%+frame_shift)
sp_frame=Y(i:(i+frame_size)).*hamming(frame_size+1);
sp_frame_dft=abs(fft(sp_frame)); % Compute STFT
sp_frame_array(:,j)=sp_frame_dft;
j=j+1;
end
%% Plot the STFT in 3D
[rows,cols]=size(sp_frame_array);
F=linspace(1/Fs,Fs/2000,cols);
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Z=1:frame_size+1;
subplot(2,1,2)
%mesh(sp_frame_array);
%surf(sp_frame_array,'EdgeColor','none');
plot3(T,F,sp_frame_array);
I am not sure what your question exactly is about, but I guess the problem is, with the provided code, that you do not get a plot similar to the one you'd get, say, with surf.
Furthermore, I am also not quite sure why you would want to use plot3, maybe to get the labels on the time and frequency right ? you could do that all the same with surf:
surf(T, F, sp_frame_array,'EdgeColor','none');
As a matter of fact, the reason why your plot3 does not give the same figure is because the arguments of plot3 must be three matrices of the same size (check it on help plot3). Your code should actually be broken on Matlab, which it's not, according to my test. Well, once again Matlab allowing people to mess around without warnings (go Python! :D)... Anyway, try to set the matrices more like the following:
F=linspace(1/Fs,Fs/2000, rows); % note: has to be rows, not cols here!
Fmat = F(:) * ones(1,cols); % or use repmat
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Tmat = ones(rows,1) * T(:)';
plot3(Tmat,Fmat,sp_frame_array);
While this will normally produce something more in line with what I would expect in drawing a spectrogram, I'd still make some remarks:
your F vector should go up to Fs, because of the way you filled sp_frame_dft in. More specifically, it should go from 0Hz to Fs - Fs/rows:
F = linspace(0,Fs*(1-1/rows)/1000,rows); % in kHz
you would probably like to draw the amplitudes in dBs:
plot3(Tmat,Fmat,db(sp_frame_array));
plot3 draws one line per column of the provided matrices. That means potentially lots of lines to draw! As #atul-ingle asked, are you sure this is what you want? Maybe waterfall would provide a better rendering at a lower cost?
waterfall(T,F,db(sp_frame_array));
Well, you'll get the lines for the rows, instead of the columns, so you might need to transpose if the latter is what you want.
You might also prefer to visualise only the first half of the matrix (because the frequencies higher than Fs/2 are only mirrors of the other half of the matrix).
Hope that helps!