Zero padding fourier of image - image

I'm trying to solve a question,
given an image f(x,y) at size N,M with fourier transform F.
we define function g, which its fourier transform G is define as follows:
G(x,y)=F(x,y) if x
which means that we pad the image with zeros.
I tried to check it out using matlab with this code:
i1 = imread('1.bmp');
i1 = im2double(i1);
k=fft2(i1);
newmat = padarray(k,[84,84],0,'post');
mat2=ifft2(newmat);
imshow(mat2);
for some reason im getting a complex matrix, which I can't really tell something intersting about,
what am I missing? (just to clarify, the image I tried has a size of 84x84).
Thanks!

The padding has to add high frequencies, which is not what you are doing. For a 1D FFT F, F(2) and F(end) correspond to the same frequency — in 2D this is exactly the same, for each image line along each image dimension. By padding with zeros by extending the array, you are creating a new F(end). That value no longer matches the one in F(2). For the inverse transform to be real-valued, those two values should be complex conjugates of each other.
The solution is to add the padding in the middle of the array, where the highest frequencies are. The easiest way to do this is to first use fftshift to move the zero frequency to the center of the array, then pad all around the array, then shift back:
k = fft2(i1);
k = fftshift(k);
k = padarray(k,[84,84]/2,'both');
k = ifftshift(k);
mat2 = ifft2(k);
This way you preserve the conjugate symmetry expected of the Fourier transform of a real-valued image.
It seems OP is confused about what happens when padding with zeros in different parts of the Fourier spectrum. Here's a little experiment:
% Create a test image, a simple Gaussian, purely real-valued
x = linspace(-3,3,84);
img = exp(-0.5*x.^2);
img = img.' * img;
imshow(img)
% OP's method
k = fft2(img);
k = padarray(k,[84,84],0,'post');
k = complex(k); % This line does nothing
out = ifft2(k) * 4;
subplot(1,2,1); imshow(real(out)); title('real part')
subplot(1,2,2); imshow(imag(out)); title('imaginary part')
% Correct method
k = fft2(img);
k = fftshift(k);
k = padarray(k,[84,84]/2,'both');
k = ifftshift(k);
out = ifft2(k) * 4;
subplot(1,2,1); imshow(real(out)); title('real part')
subplot(1,2,2); imshow(imag(out)); title('imaginary part')
As you can see, when padding 'post', you introduce an asymmetry in the Fourier domain that translates to a non-real image in the spatial domain. In contrast, padding as I instructed in this answer leads to preserving the conjugate symmetry and hence a real-valued output (the imaginary part is all black).
(sorry for all the white space around the images)

Related

Image filtering without built in function matlab [duplicate]

I have the following code in MATLAB:
I=imread(image);
h=fspecial('gaussian',si,sigma);
I=im2double(I);
I=imfilter(I,h,'conv');
figure,imagesc(I),impixelinfo,title('Original Image after Convolving with gaussian'),colormap('gray');
How can I define and apply a Gaussian filter to an image without imfilter, fspecial and conv2?
It's really unfortunate that you can't use the some of the built-in methods from the Image Processing Toolbox to help you do this task. However, we can still do what you're asking, though it will be a bit more difficult. I'm still going to use some functions from the IPT to help us do what you're asking. Also, I'm going to assume that your image is grayscale. I'll leave it to you if you want to do this for colour images.
Create Gaussian Mask
What you can do is create a grid of 2D spatial co-ordinates using meshgrid that is the same size as the Gaussian filter mask you are creating. I'm going to assume that N is odd to make my life easier. This will allow for the spatial co-ordinates to be symmetric all around the mask.
If you recall, the 2D Gaussian can be defined as:
The scaling factor in front of the exponential is primarily concerned with ensuring that the area underneath the Gaussian is 1. We will deal with this normalization in another way, where we generate the Gaussian coefficients without the scaling factor, then simply sum up all of the coefficients in the mask and divide every element by this sum to ensure a unit area.
Assuming that you want to create a N x N filter, and with a given standard deviation sigma, the code would look something like this, with h representing your Gaussian filter.
%// Generate horizontal and vertical co-ordinates, where
%// the origin is in the middle
ind = -floor(N/2) : floor(N/2);
[X Y] = meshgrid(ind, ind);
%// Create Gaussian Mask
h = exp(-(X.^2 + Y.^2) / (2*sigma*sigma));
%// Normalize so that total area (sum of all weights) is 1
h = h / sum(h(:));
If you check this with fspecial, for odd values of N, you'll see that the masks match.
Filter the image
The basics behind filtering an image is for each pixel in your input image, you take a pixel neighbourhood that surrounds this pixel that is the same size as your Gaussian mask. You perform an element-by-element multiplication with this pixel neighbourhood with the Gaussian mask and sum up all of the elements together. The resultant sum is what the output pixel would be at the corresponding spatial location in the output image. I'm going to use the im2col that will take pixel neighbourhoods and turn them into columns. im2col will take each of these columns and create a matrix where each column represents one pixel neighbourhood.
What we can do next is take our Gaussian mask and convert this into a column vector. Next, we would take this column vector, and replicate this for as many columns as we have from the result of im2col to create... let's call this a Gaussian matrix for a lack of a better term. With this Gaussian matrix, we will do an element-by-element multiplication with this matrix and with the output of im2col. Once we do this, we can sum over all of the rows for each column. The best way to do this element-by-element multiplication is through bsxfun, and I'll show you how to use it soon.
The result of this will be your filtered image, but it will be a single vector. You would need to reshape this vector back into matrix form with col2im to get our filtered image. However, a slight problem with this approach is that it doesn't filter pixels where the spatial mask extends beyond the dimensions of the image. As such, you'll actually need to pad the border of your image with zeroes so that we can properly do our filter. We can do this with padarray.
Therefore, our code will look something like this, going with your variables you have defined above:
N = 5; %// Define size of Gaussian mask
sigma = 2; %// Define sigma here
%// Generate Gaussian mask
ind = -floor(N/2) : floor(N/2);
[X Y] = meshgrid(ind, ind);
h = exp(-(X.^2 + Y.^2) / (2*sigma*sigma));
h = h / sum(h(:));
%// Convert filter into a column vector
h = h(:);
%// Filter our image
I = imread(image);
I = im2double(I);
I_pad = padarray(I, [floor(N/2) floor(N/2)]);
C = im2col(I_pad, [N N], 'sliding');
C_filter = sum(bsxfun(#times, C, h), 1);
out = col2im(C_filter, [N N], size(I_pad), 'sliding');
out contains the filtered image after applying a Gaussian filtering mask to your input image I. As an example, let's say N = 9, sigma = 4. Let's also use cameraman.tif that is an image that's part of the MATLAB system path. By using the above parameters, as well as the image, this is the input and output image we get:

How to create a mask or detect image section based on the intensity value?

I have a matrix named figmat from which I obtain the following pcolor plot (Matlab-Version R 2016b).
Basically I only want to extract the bottom red high intensity line from this plot.
I thought of doing it in some way of extracting the maximum values from the matrix and creating some sort of mask on the main matrix. But I'm not understanding a possible way to achieve this. Can it be accomplished with the help of any edge/image detection algorithms?
I was trying something like this with the following code to create a mask
A=max(figmat);
figmat(figmat~=A)=0;
imagesc(figmat);
But this gives only the boundary of maximum values. I also need the entire red color band.
Okay, I assume that the red line is linear and its values can uniquely be separated from the rest of the picture. Let's generate some test data...
[x,y] = meshgrid(-5:.2:5, -5:.2:5);
n = size(x,1)*size(x,2);
z = -0.2*(y-(0.2*x+1)).^2 + 5 + randn(size(x))*0.1;
figure
surf(x,y,z);
This script generates a surface function. Its set of maximum values (x,y) can be described by a linear function y = 0.2*x+1. I added a bit of noise to it to make it a bit more realistic.
We now select all points where z is smaller than, let's say, 95 % of the maximum value. Therefore find can be used. Later, we want to use one-dimensional data, so we reshape everything.
thresh = min(min(z)) + (max(max(z))-min(min(z)))*0.95;
mask = reshape(z > thresh,1,n);
idx = find(mask>0);
xvec = reshape(x,1,n);
yvec = reshape(y,1,n);
xvec and yvec now contain the coordinates of all values > thresh.
The last step is to do some linear polynomial over all points.
pp = polyfit(xvec(idx),yvec(idx),1)
pp =
0.1946 1.0134
Obviously these are roughly the coefficients of y = 0.2*x+1 as it should be.
I do not know, if this also works with your data, since I made some assumptions. The threshold level must be chosen carefully. Maybe some preprocessing must be done to dynamically detect this level if you really want to process your images automatically. There might also be a simpler way to do it... but for me this one was straight forward without the need of any toolboxes.
By assuming:
There is only one band to extract.
It always has the maximum values.
It is linear.
I can adopt my previous answer to this case as well, with few minor changes:
First, we get the distribution of the values in the matrix and look for a population in the top values, that can be distinguished from the smaller values. This is done by finding the maximum value x(i) on the histogram that:
Is a local maximum (its bin is higher than that of x(i+1) and x(i-1))
Has more values above it than within it (the sum of the height of bins x(i+1) to x(end) < the height of bin x):
This is how it is done:
[h,x] = histcounts(figmat); % get the distribution of intesities
d = diff(fliplr(h)); % The diffrence in bin height from large x to small x
band_min_ind = find(cumsum(d)>size(figmat,2) & d<0, 1); % 1st bin that fit the conditions
flp_val = fliplr(x); % the value of x from large to small
band_min = flp_val(band_min_ind); % the value of x that fit the conditions
Now we continue as before. Mask all the unwanted values, interpolate the linear line:
mA = figmat>band_min; % mask all values below the top value mode
[y1,x1] = find(mA,1); % find the first nonzero row
[y2,x2] = find(mA,1,'last'); % find the last nonzero row
m = (y1-y2)/(x1-x2); % the line slope
n = y1-m*x1; % the intercept
f_line = #(x) m.*x+n; % the line function
And if we plot it we can see the red line where the band for detection was:
Next, we can make this line thicker for a better representation of this line:
thick = max(sum(mA)); % mode thickness of the line
tmp = (1:thick)-ceil(thick/2); % helper vector for expanding
rows = bsxfun(#plus,tmp.',floor(f_line(1:size(A,2)))); % all the rows for each column
rows(rows<1) = 1; % make sure to not get out of range
rows(rows>size(A,1)) = size(A,1); % make sure to not get out of range
inds = sub2ind(size(A),rows,repmat(1:size(A,2),thick,1)); % convert to linear indecies
mA(inds) = true; % add the interpolation to the mask
result = figmat.*mA; % apply the mask on figmat
Finally, we can plot that result after masking, excluding the unwanted areas:
imagesc(result(any(result,2),:))

How to compute horizontal gradient value?

So I want to measure the vertical edges of an image to use it later as depth cue for 2D to 3D conversion.
To do so I will have to compute the horizontal gradient value for each block to measure the vertical edges as follow:
̅ g(x,y) = 1/N ∑_((x',y')∈ Ω(x,y))〖g(x', y')〗
Where:
g(x',y') is a horizontal gradient at a pixel location (x',y'),
omega(x,y) is the nighborhood of the pixel location(x',y')
and N is the number of pixels in omega(x,y).
So Here is what I did on matlab:
I = im2double(imread('landscape.jpg'));
% convert RGB to gray
gI = rgb2gray(I);
[nrow, ncol] = size(gI);
% divide the image into 4-by-4 blocks
gI = mat2tiles((gI),[4,4]);
N = 4*4; % block size
% For each block, compute the horizontal gradient
gI = reshape([gI{:}],4*4, []);
mask = fspecial('sobel');
g = imfilter(gI, mask);
g_bar = g./N;
g_bar = reshape(g_bar,nrow, ncol);
I'm new to Matlab so I'm not sure if my code is expressing the equation in the right way.
Can you please let me know if you think it is correct? as I'm not sure how to test the output!
There's no need for you to decompose your image into 4 x 4 blocks. The horizontal gradient can be used with a Sobel filter or Prewitt filter, which is 3 x 3 and can directly be put into imfilter. imfilter performs 2D convolution / filtering with a specified mask / kernel for you, so tiling is not necessary. As such, you can just use imfilter with the mask defined through fspecial, and define N = 9. Therefore:
I = im2double(imread('landscape.jpg'));
% convert RGB to gray
gI = rgb2gray(I);
N = 9;
mask = fspecial('sobel');
g = imfilter(gI, mask);
g_bar = g./N;
From experience, increasing the size of your gradient mask won't give you much better results. You want to ensure that the mask is as small as possible to capture as many local changes as possible.

Vector decomposition in matlab

this is my situation: I have a 30x30 image and I want to calculate the radial and tangent component of the gradient of each point (pixel) along the straight line passing through the centre of the image (15,15) and the same (i,j) point.
[dx, dy] = gradient(img);
for i=1:30
for j=1:30
pt = [dx(i, j), dy(i,j)];
line = [i-15, j-15];
costh = dot(line, pt)/(norm(line)*norm(pt));
par(i,j) = norm(costh*line);
tang(i,j) = norm(sin(acos(costh))*line);
end
end
is this code correct?
I think there is a conceptual error in your code, I tried to get your results with a different approach, see how it compares to yours.
[dy, dx] = gradient(img);
I inverted x and y because the usual convention in matlab is to have the first dimension along the rows of a matrix while gradient does the opposite.
I created an array of the same size as img but with each pixel containing the angle of the vector from the center of the image to this point:
[I,J] = ind2sub(size(img), 1:numel(img));
theta=reshape(atan2d(I-ceil(size(img,1)/2), J-ceil(size(img,2)/2)), size(img))+180;
The function atan2d ensures that the 4 quadrants give distinct angle values.
Now the projection of the x and y components can be obtained with trigonometry:
par=dx.*sind(theta)+dy.*cosd(theta);
tang=dx.*cosd(theta)+dy.*sind(theta);
Note the use of the .* to achieve point-by-point multiplication, this is a big advantage of Matlab's matrix computations which saves you a loop.
Here's an example with a well-defined input image (no gradient along the rows and a constant gradient along the columns):
img=repmat(1:30, [30 1]);
The results:
subplot(1,2,1)
imagesc(par)
subplot(1,2,2)
imagesc(tang)
colorbar

How to implement the arnold transform of image

I need to implement the arnold transformation on colour image as it is part of my project please suggest how to implement it for MxN image
In the classical sense, the continuous Arnold's map is defined on the unit square, and therefore the discrete version is defined on square images:
Consider your image as three NxN matrices; one NxN matrix for each colour channel (assuming you're working with RGB images). Do the following transformation with each of the matrices:
Map the (i,j) element of the input matrix to the ((i + j) mod N, (i + 2j) mod N) element of the output matrix.
It's a concatenation of a vertical and a horizontal shearing transformation, "wrapped around" to the original image rectangle:
(the image is from the corresponding Wikipedia article)
In pseudocode for a single colour channel:
Image arnold(inputImage){
outputImage = Image(inputImage.width, inputImage.height);
for(x = 0; x < inputImage.width; x++){
for(y = 0; y < inputImage.height; y++){
pixel = inputImage[x][y];
outputImage[(2*x + y) mod inputImage.width][(x + y) mod inputImage.height] = pixel;
}
}
return outputImage;
}
(note that conventionally we index matrices by (row,column) and images by (column,row))
So that's for square (NxN) images. What you want (Arnold's map for MxN images, where possibly M != N) is somewhat ill-posed in the sense that it's not clear whether it preserves some interesting properties of Arnold's map. However, if that doesn't bother you, you can generalize the map for MxN images the following way:
Perform a vertical shear with wrap-around in such a way, that the j-th column is circulalry shifted upward by j*M/N (note that this leaves the first column and the last column in-place) *
Perform a horizontal shear with wrap-around in such a way, that the i-th row is circulalry right-shifted by i*N/M (this leaves the first and the last row in-place) *
* : shearing is simply shifting columns/rows
Edit: updated my answer for the generalized MxN case

Resources