Applying 2D Gabor Wavelet on Image - matlab

EDIT: This is the code I am using that generates an edge detected looking image:
cookiesImage = rgb2gray(imread('Cookies.png'));
width = 45;
height = 45;
KMAX = pi / 2;
f = sqrt(2);
delta = pi / 3;
output = zeros(size(cookiesImage, 1), size(cookiesImage, 2), 8);
for i = 0 : 7
wavelets = GaborWavelet(width, height, KMAX, f, i, 2, delta);
figure(1);
subplot(1, 8, i + 1), imshow(real(wavelets), []);
output(:, :, i + 1) = imfilter(cookiesImage, wavelets, 'symmetric');
end
display = sum(abs(output).^2, 3).^0.5;
display = display./max(display(:));
figure(2); imshow(display);
function GWKernel = GaborWavelet (width, height, KMAX, f, u , v, delta)
delta2 = delta * delta;
kv = KMAX / (f^v);
thetaU = (u * pi) / 8;
kuv = kv * exp (1i * thetaU);
kuv2 = abs(kuv)^2;
GWKernel = zeros (height, width);
for y = -height/ 2 + 1 : height / 2
for x = -width / 2 + 1 : width / 2
GWKernel(y + height / 2, x + width / 2) = (kuv2 / delta2) * exp(-0.5 * kuv2 * (x * x + y * y) / delta2) * (exp(1i * (real(kuv) * y + imag (kuv) * x )) - exp (-0.5 * delta2));
end
end
This is the function that I am using for the Wavelets and this is how I am trying to apply them but all I am getting is an edge detected looking image, rather than one as in this link.

Running your code, I see the following wavelets being generated:
These look a lot like rotated second derivatives. This is only the real (even) component of the Gabor filter kernels. The imaginary (odd) counterparts look like first derivatives.
This is why you feel like your result is like an edge-detected image. It sort of is.
Try increasing the size of the filter (not the footprint widthxheight, but the delta that determines the size of the envelope). This will make it so that you see a larger portion of the sinusoid waves that form the Gabor kernel.
Next, the result image you show is the sum of the square magnitude of the individual Gabor filters. Try displaying the real or imaginary components of one of the filter results, you'll see it looks more like you'd expect:
imshow(real(output(:,:,3)),[])
I'm not familiar with this parametrization of the Gabor kernel, but note that it has a Gaussian envelope. Therefore, the footprint (width, height) of the kernel can be adjusted to the size of this Gaussian (which seems to use delta as the sigma). I typically recommend using a kernel footprint of 2*ceil(3*sigma)+1 for the Gaussian kernel. The same applies here:
width = 2*ceil(3*delta)+1;
height = width;
This will speed up computations, as you see in the image above your kernels have lots of near-zero values in them, it is possible to crop them to a smaller size without affecting the output.
The GaborWavelet function can also be simplified a lot using vectorization:
function GWKernel = GaborWavelet (width, height, KMAX, f, u , v, delta)
delta2 = delta * delta;
kv = KMAX / (f^v);
thetaU = (u * pi) / 8;
kuv = kv * exp (1i * thetaU);
kuv2 = abs(kuv)^2;
x = -width/2 + 1 : width/2;
[x,y] = meshgrid(x,x);
GWKernel = (kuv2 / delta2) * exp(-0.5 * kuv2 * (x .* x + y .* y) / delta2) ...
.* (exp(1i * (real(kuv) * y + imag (kuv) * x )) - exp (-0.5 * delta2));

Related

Speeding up code which integrates a 2D gpuArray matrix using Simpson's Rule

I have a (real) 2D gpuArray, which I am using as part of a larger code, and now am trying to also integrate the array using the Composite Simpson Rule inside my main loop (several 10000 iterations at least). A MWE looks like the following:
%%%%%%%%%%%%%%%%%% MAIN CODE %%%%%%%%%%%%%%%%%%
Ny = 501; % Dimensions of matrix M
Nx = 503; %
dx = 0.1; % Grid spacings
dy = 0.2; %
M = rand(Ny, Nx, 'gpuArray'); % Initialise a matrix
for k = 1:10000
% M = function1(M) % Apply some other functions to M
% ... etc ...
I = simpsons_integration_2D(M, dx, dy, Nx, Ny); % Now integrate M
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%% Integrator %%%%%%%%%%%%%%%%%
function I = simpsons_integration_2D(F, dx, dy, Nx, Ny)
% Integrate the 2D function F with Nx columns and Ny rows, and grid spacings
% dx and dy using Simpson's rule.
% Integrate along x direction (vertically) --> IX is a vector afterwards
sX = sum( F(:,1:2:Nx-2) + 4*F(:,2:2:(Nx-1)) + F(:,3:2:Nx) , 2);
IX = dx/3 * sX;
% Integrate along y direction --> I is a scalar afterwards
sY = sum( IX(1:2:Ny-2) + 4*IX(2:2:(Ny-1)) + IX(3:2:Ny) , 1);
I = dy/3 * sY;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The operation of performing the integration is around 850 µs, which is currently a significant part of my code. This was measured using
f = #() simpsons_integration_2D(M, dx, dy, Nx, Ny);
t = gputimeit(f)
Is there a way to reduce the execution time for integrating the gpuArray matrix?
(The graphics card is the Nvidia Quadro P4000)
Many thanks
Assuming that the matrix has odd dimensions here is a way to optimize the function:
function I = simpsons_integration_2D(F, dx, dy, Nx, Ny)
sX = 2 * sum(F,2) + 2 * sum (F(:,2:2:(Nx-1)),2) - F(:,1) - F(:,Nx);
sY = dx/3 * (2 * sum(sX) + 2 * sum (sX(2:2:(Ny-1))) - sX(1) - sX(Ny));
I = dy/3 * sY;
end
EDIT
A more optimized solution using matrix multiplication:
function I = simpsons_integration_2D2(F, dx, dy, Nx, Ny)
mx = repmat (2, Nx, 1);
mx(2:2:(Nx-1)) = 4;
mx(1) = 1;
mx(Nx) = 1;
my = repmat (2, 1, Ny);
my(2:2:(Ny-1)) = 4;
my(1) = 1;
my(Ny) = 1;
I = (dx*dy/9) * (my * (F * mx));
end
If Nx and Ny are the same you need to compute only one of them mx or my:
function I = simpsons_integration_2D2(F, dx, dy, Nx, Ny)
mx = repmat (2, Nx, 1);
mx(2:2:(Nx-1)) = 4;
mx(1) = 1;
mx(Nx) = 1;
I = (dx*dy/9) * (mx.' * (F * mx));
end
If Nx and Ny are constant you can precompute mx outside the function and pass it as a function argument:
function I = simpsons_integration_2D2(F, dx, dy, mx)
I = (dx*dy/9) * (mx.' * (F * mx));
end
EDIT:
If both mx and my can be precomputed the problem is reduced to a dot product:
m = reshape (my.' .* mx.', 1, []);
function I = simpsons_integration_2D3(F, dx, dy, m)
I = (dx*dy/9) * (m * F(:));
end
Well I cannot test this for you but there are a few things that may help.
First the axis 1 and then the the axis 2 may make some difference in terms of locality of the modified terms (I don't know if to better or to worse).
function I = variation1(F, dx, dy, Nx, Ny)
% Sum each term separately, prevents the creation of a big intermediate matrix
% Multiply outside the summation does only Ny multiplications by 4 instead of Ny*Nx/2
sX = sum(F(:,1:2:Nx-2), 2) + 4*sum(F(:,2:2:(Nx-1)), 2) + sum(F(:,3:2:Nx), 2);
IX = dx/3 * sX;
sY = sum(IX(1:2:Ny-2), 1) + 4*sum(IX(2:2:(Ny-1)), 1) + sum(IX(3:2:Ny) , 1);
I = dy/3 * sY;
end
function I = variation2(F, dx, dy, Nx, Ny)
% a.
% Sum each term separately, prevents the creation of a big intermediate matrix
% Multiply outside the summation does only Ny multiplications by 4 instead of Ny*Nx/2
% b.
% Notice that the terms 2:3:NX-2 appear in two summations
% Saves Nx*Ny/2 additions at the expense of Ny multiplications by 2
sX = 2*sum(F(:,3:2:Nx-2), 2) + 4*sum(F(:,2:2:(Nx-1)), 2) + F(:,1) + F(:,Nx);
% saves Ny multiplications by moving the constant factor after the next sum
sY = 2*sum(sX(3:2:Ny-2), 1) + 4*sum(sX(2:2:(Ny-1)), 1) + sX(1) + sX(Ny);
I = (dy*dy/9) * sY;
end
function I = alternate_simpsons_integration_2D(F, dx, dy, Nx, Ny)
% Integrate the 2D function F with Nx columns and Ny rows, and grid spacings
% dx and dy using Simpson's rule.
% Notice that sum(F(:,1:2:Nx-2) + F(:,3:2:Nx)) have all but the end poitns repeated.
IX = 4*sum(F(:,2:2:Nx-1), 2) + 2 * sum(F(:,3:2:Nx-2) , 2) + F(:,1) + F(:,Nx);
disp(size(IX))
% Integrate along y direction --> I is a scalar afterwards
sY = 4*sum(IX(2:2:Ny-1)) + 2*sum(IX(3:2:Ny-2)) + IX(1) + IX(Ny);
I = dy*dy/9 * sY;
end
If you think it is better to make a single summation then you can do using the formula 2*(sum(2*F(2:2:end-1) + F(1:2:end-2)) + F(end) - F(1) that gives the same result but has Nx*Ny/2 less additions on the first integration. But these options have to be tested in your environment.
Transposed implementation
function I = transposed_simpsons_integration_2D(F, dx, dy, Nx, Ny)
sY = 2*sum(2*F(2:2:end-1, :) + F(1:2:end-2, :), 1) + F(end, :) - F(1, :);
sX = 2*sum(2*sY(2:2:end-1) + sY(1:2:end-2)) + sY(end) - sY(1);
I = dy*dy/9 * sX;
end
Using octave (usually slower than matlab) I get a run time of ~400us per iteration with. This is not the type of workload that will be interesting to run on the GPU. For comparison, randn about 10 times slower than this function.

Convert Fisheye Video into regular Video

I have a video stream coming from a 180 degree fisheye camera. I want to do some image-processing to convert the fisheye view into a normal view.
After some research and lots of read articles I found this paper.
They describe an algorithm (and some formulas) to solve this problem.
I used tried to implement this method in a Matlab. Unfortunately it doesn't work, and I failed to make it work. The "corrected" image looks exactly like the original photograph and there's no any removal of distortion and secondly I am just receiving top left side of the image, not the complete image but changing the value of 'K' to 1.9 gives mw the whole image, but its exactly the same image.
Input image:
Result:
When the value of K is 1.15 as mentioned in the article
When the value of K is 1.9
Here is my code:
image = imread('image2.png');
[Cx, Cy, channel] = size(image);
k = 1.5;
f = (Cx * Cy)/3;
opw = fix(f * tan(asin(sin(atan((Cx/2)/f)) * k)));
oph = fix(f * tan(asin(sin(atan((Cy/2)/f)) * k)));
image_new = zeros(opw, oph,channel);
for i = 1: opw
for j = 1: oph
[theta,rho] = cart2pol(i,j);
R = f * tan(asin(sin(atan(rho/f)) * k));
r = f * tan(asin(sin(atan(R/f))/k));
X = ceil(r * cos(theta));
Y = ceil(r * sin(theta));
for k = 1: 3
image_new(i,j,k) = image(X,Y,k);
end
end
end
image_new = uint8(image_new);
warning('off', 'Images:initSize:adjustingMag');
imshow(image_new);
This is what solved my problem.
input:
strength as floating point >= 0. 0 = no change, high numbers equal stronger correction.
zoom as floating point >= 1. (1 = no change in zoom)
algorithm:
set halfWidth = imageWidth / 2
set halfHeight = imageHeight / 2
if strength = 0 then strength = 0.00001
set correctionRadius = squareroot(imageWidth ^ 2 + imageHeight ^ 2) / strength
for each pixel (x,y) in destinationImage
set newX = x - halfWidth
set newY = y - halfHeight
set distance = squareroot(newX ^ 2 + newY ^ 2)
set r = distance / correctionRadius
if r = 0 then
set theta = 1
else
set theta = arctangent(r) / r
set sourceX = halfWidth + theta * newX * zoom
set sourceY = halfHeight + theta * newY * zoom
set color of pixel (x, y) to color of source image pixel at (sourceX, sourceY)

Matlab - Plotting with for loop

I am new to matlab and am trying to loop through an equation from 1 to 1000 and plot the result, but every value is turning out the same and the plot is incrorrect.
Here is my current attempt, but the variable Rm is giving only one results (instead of 1000 separate ones):
Ds = 1.04e-10;
Gamma = 1.9;
Omega = 1.09e-29;
Deltas = 2.5e-10;
Boltzmann = 1.3806e-23;
T = 1123.15;
Beta = 0.83;
Zo = 6.7;
EtaNi = 0.39;
EtaYSZ = 0.61;
Rm0 = 0.29;
RmYSZ0 = 0.265;
lambda = 4.70e-3;
C = Ds * ((Gamma * Omega * Deltas) / (2 * Boltzmann * T)) * (Beta / ((1 - Beta^2) * ((1 + Beta^2)^0.5) * ((1 + Beta)^3))) * Zo * (EtaNi/((EtaNi/Rm0) + (EtaYSZ/RmYSZ0)));
tinit=1; % Initial time value (h)
tend=1000; % End time value (h)
tinc=1; % Increment in time value (h)
t= [tinit:tinc:tend]; % Time vector
n = 1000;
for i=1:n
Rm(i) = (((5*C)/lambda) * (1 - exp(-lambda*i)) + (Rm0)^5)^(1/5);
end
plot(t,Rm);
Expected result is an exponential curve, any help would be appreciated
Your term before R0 is an exponential that ranges from 0 to 4.5e-27. R0^5 is 0.0021. Floating point precision is not enough to preserve the first term when it is added to the second. So (5C/L*(...) + Rm0^5) == Rm0^5, so it is constant.

How to create diagonal stripe patterns and checkerboard patterns?

Based on this question, I can confirm that horizontal patterns can be imposed onto a matrix (which in this case is an image), by multiplying it with a modulation signal created with this:
vModulationSignal = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
It would also be great if someone could explain to why the above modulation signal works.
Now I want to create diagonal patterns such as :
And criss-cross (checkered) patterns such as this:
using a similar vModulationSignal
Code Excerpt where the modulation signal is created
numRows = size(mInputImage, 1);
numCols = size(mInputImage, 2);
signalFreq = floor(numRows / 1.25);
vModulationSignal = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
mOutputImage = bsxfun(#times, mInputImage, vModulationSignal);
Code Excerpt where I'm trying to create the criss cross signal
numRows = size(mInputImage, 1);
numCols = size(mInputImage, 2);
signalFreq1 = floor(numRows / 1.25);
signalFreq2 = floor(numCols / 1.25);
vModulationSignal1 = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
vModulationSignal2 = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
mOutputImage = bsxfun(#times, mInputImage, vModulationSignal);
figure();
imshow(mOutputImage);
For horizontal, vertical, diagonal stripes:
fx = 1 / 20; % 1 / period in x direction
fy = 1 / 20; % 1 / period in y direction
Nx = 200; % image dimension in x direction
Ny = 200; % image dimension in y direction
[xi, yi] = ndgrid(1 : Nx, 1 : Ny);
mask = sin(2 * pi * (fx * xi + fy * yi)) > 0; % for binary mask
mask = (sin(2 * pi * (fx * xi + fy * yi)) + 1) / 2; % for gradual [0,1] mask
imagesc(mask); % only if you want to see it
just choose fx and fy accordingly (set fy=0 for horizontal stripes, fx=0 for vertical stripes and fx,fy equal for diagonal stripes). Btw. the period of the stripes (in pixels) is exactly
period_in_pixel = 1 / sqrt(fx^2 + fy^2);
For checkerboard patterns:
f = 1 / 20; % 1 / period
Nx = 200;
Ny = 200;
[xi, yi] = ndgrid(1 : Nx, 1 : Ny);
mask = sin(2 * pi * f * xi) .* sin(2 * pi * f * yi) > 0; % for binary mask
mask = (sin(2 * pi * f * xi) .* sin(2 * pi * f * yi) + 1) / 2; % for more gradual mask
imagesc(mask);
Here the number of black and white squares per x, y direction is:
number_squares_x = 2 * f * Nx
number_squares_y = 2 * f * Ny
And if you know the size of your image and the number of squares that you want, you can use this to calculate the parameter f.
Multiplying the mask with the image:
Now that is easy. The mask is a logical (white = true, black = false). Now you only have to decide which part you want to keep (the white or the black part).
Multiply your image with the mask
masked_image = original_image .* mask;
to keep the white areas in the mask and
masked_image = original_image .* ~mask;
for the opposite.
This is actually an extension of Trilarion's answer that gives better control on stripes appearance:
function out = diagStripes( outSize, stripeAngle, stripeDistance, stripeThickness )
stripeAngle = wrapTo2Pi(-stripeAngle+pi/2);
if (stripeAngle == pi/2) || (stripeAngle == 3*pi/2)
f = #(fx, fy, xi, yi) cos(2 * pi * (fy * yi)); % vertical stripes
elseif (stripeAngle == 0)||(stripeAngle == pi)
f = #(fx, fy, xi, yi) cos(2 * pi * (fx * xi)); % horizontal stripes
else
f = #(fx, fy, xi, yi) cos(2 * pi * (fx * xi + fy * yi)); % diagonal stripes
end
if numel(outSize) == 1
outSize = [outSize outSize];
end;
fx = cos(stripeAngle) / stripeDistance; % period in x direction
fy = sin(stripeAngle) / stripeDistance; % period in y direction
Nx = outSize(2); % image dimension in x direction
Ny = outSize(1); % image dimension in y direction
[yi, xi] = ndgrid((1 : Ny)-Ny/2, (1 : Nx)-Nx/2);
mask = (f(fx, fy, xi, yi)+1)/2; % for gradual [0,1] mask
out = mask < (cos(pi*stripeThickness)+1)/2; % for binary mask
end
outSize is a two or one element vector that gives the dimensions of output image in pixels, stripeAngle gives the slope of stripes in radians, stripeDistance is the distance between centers of stripes in pixels and stripeDistance is a float value in [0 .. 1] that gives the percent of coverage of (black) stripes in (white) background.
There're also answers to the other question for generating customized checkerboard patterns.

Writing Own fft2() Function on MATLAB

I want to write my own 2 Dimensional DFT function with reduced loops.
What I try to implement is Discrete Fourier Transform:
Using the separability property of transform (actually exponential function), we can write this as multiplication of two 1 dimensional DFT. Then, we can calculate the exponential terms for rows (the matrix wM below) and columns (the matrix wN below) of transform. Then, for summation process we can multiply them as "F = wM * original_matrix * wN"
Here is the code I wrote:
f = imread('cameraman.tif');
[M, N, ~] = size(f);
wM = zeros(M, M);
wN = zeros(N, N);
for u = 0 : (M - 1)
for x = 0 : (M - 1)
wM(u+1, x+1) = exp(-2 * pi * 1i / M * x * u);
end
end
for v = 0 : (N - 1)
for y = 0 : (N - 1)
wN(y+1, v+1) = exp(-2 * pi * 1i / N * y * v);
end
end
F = wM * im2double(f) * wN;
The first thing is I dont want to use 2 loops which are MxM and NxN times running. If I used a huge matrix (or image), that would be a problem. Is there any chance to make this code faster (for example eliminating the loops)?
The second thing is displaying the Fourier Transform result. I use the codes below to display the transform:
% // "log" method
fl = log(1 + abs(F));
fm = max(fl(:));
imshow(im2uint8(fl / fm))
and
% // "abs" method
fa = abs(F);
fm = max(fa(:));
imshow(fa / fm)
When I use the "abs" method, I see only black figure, nothing else. What is wrong with "abs" method you think?
And the last thing is when I compare the transform result of my own function with MATLAB' s fft2() function', mine displays darker figure than MATLAB' s result. What am I missing here? Implementation misktake?
The transform result of my own function:
The transform result of MATLAB fft2() function:
I am happy you solved your problem but unfortunately you answer is not completely right. Indeed it does the job, but as I commented, im2double will normalize everything to 1, therefore showing the scaled result you have. What you want (if you are looking for performance) is not doing im2doubleand then multiply by 255, but directly casting to double().
You can eliminate loops by using meshgrid.
For example:
M = 1024;
tic
[ mX, mY ] = meshgrid( 0 : M - 1, 0 : M - 1 );
wM1 = exp( -2 * pi * 1i / M .* mX .* mY );
toc
tic
for u = 0 : (M - 1)
for x = 0 : (M - 1)
wM2( u + 1, x + 1 ) = exp( -2 * pi * 1i / M * x * u );
end
end
toc
all( wM1( : ) == wM2( : ) )
The timing on my system was:
Elapsed time is 0.130923 seconds.
Elapsed time is 0.493163 seconds.