MATLAB function for image filtering - matlab

I'm looking to implement my own Matlab function that can be used to compute image filtering with a 3x3 kernel.
It has to be like this: function [ output_args ] = fFilter( img, mask )
where img is a original image and mask is a kernel (for example B = [1,1,1;1,4,1;1,1,1] )
I'm not supposed to use any in-built functions from Image Processing Toolbox.
I have to use this
where:
s is an image after filter
p is an image before filter
M is a kernel
and N is 1 if sum(sum(M)) == 0 else N = sum(sum(M))
I'm new to MATLAB and this is like black magic for me -_-

This should do the work (Wasn't verified):
function [ mO ] = ImageFilter( mI, mMask )
%UNTITLED2 Summary of this function goes here
% Detailed explanation goes here
numRows = size(mI, 1);
numCols = size(mI, 2);
% Assuming Odd number of Rows / Columns
maskRadius = floor(siez(mMask, 1) / 2);
sumMask = sum(mMask(:));
if(sumMask ~= 0)
mMask(:) = mMask / sumMask;
end
mO = zeros([numRows, numCols]);
for jj = 1:numCols
for ii = 1:numRows
for kk = -maskRadius:maskRadius
nn = kk + 1; %<! Mask Index
colIdx = min(max(1, jj + kk), numCols); %<! Replicate Boundary
for ll = -maskRadius:maskRadius
mm = ll + 1; %<! Mask Index
rowIdx = min(max(1, ii + ll), numRows); %<! Replicate Boundary
mO(ii, jj) = mO(ii, jj) + (mMask(mm, nn) * mI(rowIdx, colIdx));
end
end
end
end
end
The above is classic Correlation (Image Filtering) with Replicate Boundary Condition.

Related

How to change Euclidean distance to Mahalanobis distance in my MATLAB code?

I am trying to segment an image for a given k value using k-means clustering algorithm.
I want to change the distance calculation from Euclidean to Mahalanobis distance But I cannot implement the formula to my existing code because it has three dimensional array.
First I convert RGB image into HSL space. Then I label the pixels after distance calculation. In the last step I convert HSL image back into RGB space.
nC = uint8(input('Enter cluster number: '));
iRGB = double(imread('Bird.png'));
tic
iHSL = rgb2hsl(iRGB/255);
[ro co bd ] = size(iHSL);
% Randomly assign cluster positions
Cs = [randi(ro, nC,1) randi(co, nC,1)];
%create array for labels
Ls = zeros(ro, co);
%create another array for comparison of labels
prev_Ls = ones(ro, co);
distances = zeros( 1, nC );
kcenter = zeros(nC, 3);
for k=1:nC
kcenter(k,:) = iHSL(kcenter(k),kcenter(k,2),:);
end
while (true)
prev_Ls = Ls;
for r = 1:ro
for c = 1:co
for k = 1:nC
distances(k) = sqrt(((iHSL(r,c,1) - kcenter(k,1))^2 +...
(iHSL(r,c,2) - kcenter(k,2))^2 +...
(iHSL(r,c,3) - kcenter(k,3))^2));
end
d = find(distances(:) == min(distances));
Ls(r,c) = d(1);
end
end
H = zeros(1,nC);
S = zeros(1,nC);
L = zeros(1,nC);
cnt = zeros(1,nC);
for r = 1:ro
for c = 1:co
H( Ls(r,c) ) = H( Ls(r,c) ) + iHSL(r,c,1);
S( Ls(r,c) ) = S( Ls(r,c) ) + iHSL(r,c,2);
L( Ls(r,c) ) = L( Ls(r,c) ) + iHSL(r,c,3);
cnt( Ls(r,c) ) = cnt( Ls(r,c) ) + 1;
end
end
for k = 1:nC
kcenter(k,1) = H(k) / cnt(k);
kcenter(k,2) = S(k) / cnt(k);
kcenter(k,3) = L(k) / cnt(k);
end
%if prev_labels are equal to current labels break while loop.
if isequal(prev_Ls, Ls)
break;
end
end
for r = 1:ro
for c = 1:co
iHSL(r,c,1) = kcenter(Ls(r,c), 1);
iHSL(r,c,2) = kcenter(Ls(r,c), 2);
iHSL(r,c,3) = kcenter(Ls(r,c), 3);
end
end
result_img = hsl2rgb(iHSL)*255;
toc
figure(1);
subplot(1,2,1);
imshow(uint8(iRGB));
subplot(1,2,2);
imshow(uint8(result_img));
I want to change this formula with mahalanobis distance calculation formula. I have tried mahal(iHSL(r,c,1),kcenter(k,1)) I got Nan result.
All the examples on the Internet are for two dimensional arrays. But I have 3 dimensional.
I have tried to change this line;
distances(k) = sqrt((iHSL(r,c,1) - kcenter(k,1))^2 +...
(iHSL(r,c,2) - kcenter(k,2))^2 +...
(iHSL(r,c,3) - kcenter(k,3))^2);
to;
distances(k) = mahal(kcenter(k,:), iHSL(:,:,1)) + ...
mahal(kcenter(k,:), iHSL(:,:,2)) + ...
mahal(kcenter(k,:), iHSL(:,:,3));
But it gives me an error saying:
Error using mahal (line 34) Requires the inputs to have the same number of columns.
I do not know how to formulate Mahalanobis distance calculation for my 3d array.

Implementation of shadow free 1d invariant image

I implemented a method for removing shadows based on invariant color features found in the paper Entropy Minimization for Shadow Removal. My implementation seems to be yielding similar computational results sometimes, but they are always off, and my grayscale image is blocky, maybe as a result of incorrectly taking the geometric mean.
Here is an example plot of the information potential from the horse image in the paper as well as my invariant image. Multiply the x-axis by 3 to get theta(which goes from 0 to 180):
And here is the grayscale Image my code outputs for the correct maximum theta (mine is off by 10):
You can see the blockiness that their image doesn't have:
Here is their information potential:
When dividing by the geometric mean, I have tried using NaN and tresholding the image so the smallest possible value is .01, but it doesn't seem to change my output.
Here is my code:
I = im2double(imread(strname));
[m,n,d] = size(I);
I = max(I, .01);
chrom = zeros(m, n, 3, 'double');
for i = 1:m
for j = 1:n
% if ((I(i,j,1)*I(i,j,2)*I(i,j,3))~= 0)
chrom(i,j, 1) = I(i,j,1)/((I(i,j,1)*I(i,j,2)*I(i,j, 3))^(1/3));
chrom(i,j, 2) = I(i,j,2)/((I(i,j,1)*I(i,j,2)*I(i,j, 3))^(1/3));
chrom(i,j, 3) = I(i,j,3)/((I(i,j,1)*I(i,j,2)*I(i,j, 3))^(1/3));
% else
% chrom(i,j, 1) = 1;
% chrom(i,j, 2) = 1;
% chrom(i,j, 3) = 1;
% end
end
end
p1 = mat2gray(log(chrom(:,:,1)));
p2 = mat2gray(log(chrom(:,:,2)));
p3 = mat2gray(log(chrom(:,:,3)));
X1 = mat2gray(p1*1/(sqrt(2)) - p2*1/(sqrt(2)));
X2 = mat2gray(p1*1/(sqrt(6)) + p2*1/(sqrt(6)) - p3*2/(sqrt(6)));
maxinf = 0;
maxtheta = 0;
data2 = zeros(1, 61);
for theta = 0:3:180
M = X1*cos(theta*pi/180) - X2*sin(theta*pi/180);
s = sqrt(std2(X1)^(2)*cos(theta*pi/180) + std2(X2)^(2)*sin(theta*pi/180));
s = abs(1.06*s*((m*n)^(-1/5)));
[m, n] = size(M);
length = m*n;
sources = zeros(1, length, 'double');
count = 1;
for x=1:m
for y = 1:n
sources(1, count) = M(x , y);
count = count + 1;
end
end
weights = ones(1, length);
sigma = 2*s;
[xc , Ak] = fgt_model(sources , weights , sigma , 10, sqrt(length) , 6 );
sum1 = sum(fgt_predict(sources , xc , Ak , sigma , 10 ));
sum1 = sum1/sqrt(2*pi*2*s*s);
data2(theta/3 + 1) = sum1;
if (sum1 > maxinf)
maxinf = sum1;
maxtheta = theta;
end
end
InvariantImage2 = cos(maxtheta*pi/180)*X1 + sin(maxtheta*pi/180)*X2;
Assume the Fast Gauss Transform is correct.
I don't know whether this makes any difference as it is more than a month now, but the blockiness and different information potential plot is simply caused by compression of the used image. You can't expect to be getting same results using this image as they had, because they have used raw, high resolution uncompressed version of it. I have to say I am fairly impressed with your results, especially with implementing the information potential. That thing went over my head a little.
John.

Prewitt Filter implementation Matlab

I'm trying to implement the Prewitt Filter in Matlab. I know that Matlab has already this kind of filter but I need to code it myself. Below is my code, the only problem is that at the end of the filtering I get a bright image instead of seeing the edges.
I'm implementing the filter using the separability property of the Prewitt Filter. Any ideas? I will appreciate very much your help.
%% 3x3 Prewitt Filter
close all
imageIn = imread('images/Bikesgray.jpg');
imageGx = zeros(size(imageIn));
imageGy = zeros(size(imageIn));
imageOut = zeros(size(imageIn));
ny = size(imageIn, 1);
nx = size(imageIn, 2);
average = 3;
imshow(imageIn);
u = [];
v = [];
tic
%Compute Gx
%For every row use the mask (-1 0 1)
for i = 1:ny
u = imageIn(i,:);
v = zeros(1, nx);
for k = 2:nx-1
v(k) = (uint32(-1*u(k-1))+uint32(0*u(k))+uint32(u(k+1)));
end
v(1) = (uint32(-1*u(2))+uint32(0*u(1))+uint32(u(2)));
v(nx) = (uint32(-1*u(nx-1))+uint32(0*u(nx))+uint32(u(nx-1)));
imageGx(i,:) = v;
end
%For every column use the mask (1 1 1)
for j = 1:nx
u = imageGx(:,j);
v = zeros(ny, 1);
for k = 2:ny-1
v(k) = (uint32(u(k-1))+uint32(u(k))+uint32(u(k+1)));
end
v(1) = (uint32(u(2))+uint32(u(1))+uint32(u(2)));
v(ny) = (uint32(u(ny-1))+uint32(u(ny))+uint32(u(ny-1)));
imageGx(:,j) = v;
end
%Compute Gy
%For every row use the mask (1 1 1)
for i = 1:ny
u = imageIn(i,:);
v = zeros(1, nx);
for k = 2:nx-1
v(k) = (uint32(u(k-1))+uint32(u(k))+uint32(u(k+1)));
end
v(1) = (uint32(u(2))+uint32(u(1))+uint32(u(2)));
v(nx) = (uint32(u(nx-1))+uint32(u(nx))+uint32(u(nx-1)));
imageGy(i,:) = v;
end
%For every column use the mask (1 0 -1)
for j = 1:nx
u = imageGy(:,j);
v = zeros(ny, 1);
for k = 2:ny-1
v(k) = (uint32(u(k-1))+uint32(0*u(k))+uint32(-1*u(k+1)));
end
v(1) = (uint32(u(2))+uint32(0*u(1))+uint32(-1*u(2)));
v(ny) = (uint32(u(ny-1))+uint32(0*u(ny))+uint32(-1*u(ny-1)));
imageGy(:,j) = v;
end
toc
figure
imshow(imageGx, [0 255]);
figure
imshow(imageGy, [0 255]);
%Compute the magnitude G = sqrt(Gx^2 + Gy^2);
imageOut(:,:) = sqrt(imageGx(:,:).^2 + imageGy(:,:).^2);
figure
imshow(imageOut, [0 255]);
It's too bad you didn't use convn (convolution), since the weighted sum just screams it.
In a nutshell you produce Gx,Gy by using convn on the image matrix, using the appropriate kernels, as described in wikipedia
The solution was really obvious but took me some time to figure it out.
All I did is change the uint32 to int32 and be sure to perform the operations (e.g. multiplying by -1) after changing the values from uint32 to int32.

Double Summation in MATLAB and vectorized loops

Here's my attempt in implementing this lovely formula.
http://dl.dropbox.com/u/7348856/Picture1.png
%WIGNER Computes Wigner-Distribution on an image (difference of two images).
function[wd] = wigner(difference)
%Image size
[M, N, ~] = size(difference);
%Window size (5 x 5)
Md = 5;
Nd = 5;
%Fourier Transform
F = fft2(difference);
%Initializing the wigner picture
wd = zeros(M, N, 'uint8');
lambda =0.02;
value = (4/(Md*Nd));
for x = 1+floor(Md/2):M - floor(Md/2)
for y = 1+floor(Nd/2):N - floor(Nd/2)
for l = -floor(Nd/2) : floor(Nd/2)
for k = -floor(Md/2) : floor(Md/2)
kernel = exp(-lambda * norm(k,l));
kernel = kernel * value;
theta = 4 * pi * ((real(F(x, y)) * (k/M) )+ (imag(F(x, y)) * (l/N)));
wd(x, y) = (wd(x, y)) + (cos(theta) * difference(x + k, y + l) * difference(x - k, y - l) * (kernel));
end
end
end
end
end
As you can see, the outer two loops are for the sliding window, while the remaining inner ones are for the variables of the summation.
Now, my request for you my beloved stackoverflow users is: Can you help me improve these very nasty for loops that take more than its share of time, and turn it into vectorized loops?
And will that improvement be of a significant change?
Thank you.
this might not be what you are asking, but it seems (at first glance) that the order of the summations are independent and that instead of {x,y,l,k} you could go {l,k,x,y}. doing this will allow you to evaluate kernel fewer times by keeping it in the outer most loop.
Those four nested loops are basically processing each pixel in the image in a sliding-neighborhood style. I immediately thought of NLFILTER and IM2COL functions.
Here is my attempt at vectorizing the code. Note that I haven't thoroughly tested it, or compared performance against loop-based solution:
function WD = wigner(D, Md, Nd, lambda)
%# window size and lambda
if nargin<2, Md = 5; end
if nargin<3, Nd = 5; end
if nargin<4, lambda = 5; end
%# image size
[M,N,~] = size(D);
%# kernel = exp(-lambda*norm([k,l])
[K,L] = meshgrid(-floor(Md/2):floor(Md/2), -floor(Nd/2):floor(Nd/2));
K = K(:); L = L(:);
kernel = exp(-lambda .* sqrt(K.^2+L.^2));
%# frequency-domain part
F = fft2(D);
%# f(x+k,y+l) * f(x-k,y-l) * kernel
C = im2col(D, [Md Nd], 'sliding');
X1 = bsxfun(#times, C .* flipud(C), kernel);
%# cos(theta)
C = im2col(F, [Md Nd], 'sliding');
C = C(round(Md*Nd/2),:); %# take center pixels
theta = bsxfun(#times, real(C), K/M) + bsxfun(#times, imag(C), L/N);
X2 = cos(4*pi*theta);
%# combine both parts for each sliding-neighborhood
WD = col2im(sum(X1.*X2,1), [Md Nd], size(F), 'sliding') .* (4/(M*N));
%# pad array with zeros to be of same size as input image
WD = padarray(WD, ([Md Nd]-1)./2, 0, 'both');
end
For what its worth, here is the loop-based version with the improvement that #Laurbert515 suggested:
function WD = wigner_loop(D, Md, Nd, lambda)
%# window size and lambda
if nargin<2, Md = 5; end
if nargin<3, Nd = 5; end
if nargin<4, lambda = 5; end
%# image size
[M,N,~] = size(D);
%# frequency-domain part
F = fft2(D);
WD = zeros([M,N]);
for l = -floor(Nd/2):floor(Nd/2)
for k = -floor(Md/2):floor(Md/2)
%# kernel = exp(-lambda*norm([k,l])
kernel = exp(-lambda * norm([k,l]));
for x = (1+floor(Md/2)):(M-floor(Md/2))
for y = (1+floor(Nd/2)):(N-floor(Nd/2))
%# cos(theta)
theta = 4 * pi * ( real(F(x,y))*k/M + imag(F(x,y))*l/N );
%# f(x+k,y+l) * f(x-k,y-l)* kernel
WD(x,y) = WD(x,y) + ( cos(theta) * D(x+k,y+l) * D(x-k,y-l) * kernel );
end
end
end
end
WD = WD * ( 4/(M*N) );
end
and how I test it (based on what I understood from the paper you previously linked to):
%# difference between two consecutive frames
A = imread('AT3_1m4_02.tif');
B = imread('AT3_1m4_03.tif');
D = imsubtract(A,B);
%#D = rgb2gray(D);
D = im2double(D);
%# apply Wigner-Distribution
tic, WD1 = wigner(D); toc
tic, WD2 = wigner_loop(D); toc
figure(1), imshow(WD1,[])
figure(2), imshow(WD2,[])
you might then need to scale/normalize the matrix, and apply thresholding...

Canny edge detector in MATLAB

I am trying to perform canny edge detector without calling the canny function in Matlab. I wrote a few functions for the gaussian filter(sigma = 1) and non-maximum suppression. The original image and the resultant image is shown.. Not sure what the error...
The original image is
The output i get is
I have attached the code :
%% Read in
I = imread('fruit.jpg');
figure(1),imshow(I)
I = double(I);
%% Determine Mask Size
sigma = 2;
w = mask_size(sigma);
%% Gaussian Smoothing Filter
[ G,sum ] = gauss_mask(w,sigma);
%% Convolve
I1 = (1/sum) * image_convolution(I,w,G);
figure(2),imshow(I1);
%% Ix(derivative in x-direction)
Ix= delx(I1);
figure(3),imshow(Ix);
%% Iy(derivative in y-direction)
Iy= dely(I1);
figure(4),imshow(Iy);
%% Gradient Magnitude
If = grad_mag(Ix,Iy);
figure(5),imshow(If);
%% Non-maxmimum suppression
It = suppression(If,abs(Ix),abs(Iy));
figure(6),imshow(It);
function [ G,sum ] = gauss_mask( w,sigma )
min = 1;
m = floor(w/2);
sum = 0;
for x = 1: w
for y = 1:w
g = x-m-1;
h = y-m-1;
k = -(g^2 +h^2)/(2*sigma^2);
G(x,y) = exp(k);
sum = sum + G(x,y);
if min > G(x,y)
min = G(x,y);
end
end
end
B=1/min;
G= B * G;
G = round(G);
end
function [ I2 ] = image_convolution(I,w,G)
m= (w-1)/2;
N= size(I,1);
M=size(I,2);
for i=1:N
for j=1:M
if (i > N-m-1 || j > M-m-1 || i<m+1 || j <m+1)
I2(i,j) = 0;
continue;
end
sum1 = 0;
for u=1:w
for v=1:w
sum1 = sum1+I(i+u-m-1,j+v-m-1)*G(u,v);
end
end
I2(i,j)=sum1;
end
end
end
function [ Ix ] = delx( image )
mask = [-1 0 1; -2 0 2; -1 0 1];
Ix =image_convolution(image,3,mask);
end
function [ Iy ] = dely( image )
mask = [-1 -2 -1;0 0 0;1 2 1];
Iy =image_convolution(image,3,mask);
end
function [ Imag ] = grad_mag(Ix,Iy)
m=size(Ix,1);
n=size(Ix,2);
for i=1:m
for j=1:n
Imag(i,j) =sqrt(Ix(i,j)^2 + Iy(i,j)^2);
end
end
end
function [ It ] = suppression( If,Ix,Iy )
m=size(Ix,1);
n=size(Ix,2);
for i = 1:m
for j=1:n
if (j == 1 || j == n || i == 1 || j == n)
It(i,j) = 0;
else if (Ix(i,j)*Iy(i,j)> 0)
f1 =If(i-1,j-1);
f2 =If(i,j);
f3 =If(i+1,j+1);
It(i,j) = thinning(f1,f2,f3);
else if(Ix(i,j)*Iy(i,j)< 0)
f1 =If(i+1,j-1);
f2 =If(i,j);
f3 =If(i-1,j+1);
It(i,j) = thinning(f1,f2,f3);
else if(abs(Ix(i,j))-abs(Iy(i,j))>5)
f1 =If(i-1,j);
f2 =If(i,j);
f3 =If(i+1,j);
It(i,j) = thinning(f1,f2,f3);
else if(abs(Iy(i,j))-abs(Ix(i,j)) > 5)
f1 =If(i,j-1);
f2 =If(i,j);
f3 =If(i,j+1);
It(i,j) = thinning(f1,f2,f3);
end
end
end
end
end
end
end
end
function [ w ] = thinning( f1,f2,f3 )
if( f2>f1 && f2>f3)
w =1;
else
w= 0;
end
end
function sz = mask_size(sigma)
sz = floor(6*sigma) + 1;
end
There is a lot of noise... how can i solve the error? i need some help....
Error is actually at thinning function.
if( f2>f1 && f2>f3)
w =f2;
else
w= 0;
You should do both:
Smooth image to eliminate noise (conv with a gaussian matrix) before do any manipulation on it.
Take a higher threshold in Hysteresis part of the algorithm:
Take larger T1 when you do this part of the algorithm:
Define two thresholds T1 > T2
for every pixel with value greater than T1 is presumed to be an edge pixel.
Your problem is at thresholding add a strong thresholder to get rid of false edges.
First you have to smooth image with a Gaussian function. Then find gradient and magnitude of input image. Perform nonmaxima suppression. After that do hysteresis thresholding.
Seeing your Output Edge Image, I can say that You should check..
Hysteresis Function is working properly or not
You may take HIGH threshold little higher
you can smooth the image little more.