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
Related
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)
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:
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
I need to apply a function to each pixel of each image in a set of ~400 images. The function I wrote (called customf) requires 3 arguments: the matrix, and the position of the cell in the matrix (m and n). The position of the pixel is needed in order to compute the LBP (local binary pattern) which requires the values of surrounding pixels.
customf(matrix, m, n) returns an integer d so that 0 < d < 256, and I would like to store each value of d in a matrix of the same size as my image.
given that the set is quite large, I'd like my code to be as efficient as possible, but I don't understand how to use cellfun or arrayfun in such a way.
or is it a better solution? (using nested for might be inefficient?)
thanks!
Can you write customf in a different way? Instead of working on the entire image for each pixel (m, n), why don't you give it only a local patch required for computing the LBP of the patch's central pixel?
For example, if customf needs to look at pixels -/+ k away from m, n to compute the response d at m, n, then you may have
k = 5;
localF = #( patch ) customf( patch, k+1, k+1 ); % assuming patch is of size (2k+1)x(2k+1)
% apply LBP to an image
D = nlfilter( image, [2*k+1 2*k+1], localF );
Note that nlfilter zero-pads image in order to obtain D with the same size as image.
I have shapes constructed out of 8x8 squares. I need to tile them using the fewest number of squares of size 8x8, 16x16, 32x32 and 64x64. Four 8x8 squares arranged in a square can be replaced by a single 16x16 square, e.g.:
What algorithm can be used to achieve this?
This calls for a dynamic programming solution. I'll assume we have a square[r][c] array of booleans which is true if (r, c) has a 1x1 square (I've simplified the solution to work with 1x1, 2x2, 4x4 and 8x8 squares to make it easier to follow, but it's easy to adapt). Pad it with a wall of false sentinel values on the top row and left column.
Define a 2d count array, where count[r][c] refers to the number of 1x1 squares in the region above and to the left of (r, c). We can add them up using a dp algorithm:
count[0..n][0..m] = 0
for i in 1..n:
for j in 1..m:
count[i][j] = count[i-1][j] + count[i][j-1] -
count[i-1][j-1] + square[i][j]
The above works by adding up two regions we already know the sum of, subtracting the doubly-counted area and adding in the new cell. Using the count array, we can test if a square region is fully covered in 1x1 squares in constant time using a similar method:
// p1 is the top-left coordinate, p2 the bottom-right
function region_count(p1, p2):
return count[p1.r][p1.c] - count[p1.r][p2.c-1] -
count[p2.r-1][p1.c] + 2*count[p2.r-1][p2.c-1]
We then create a second 2d min_squares array, where min_squares[r][c] refers to the minimum number of squares required to cover the original 1x1 squares. These values can be calculates using another dp:
min_squares = count
for i in 1..n:
for j in 1..m:
for size in [2, 4, 8]:
if i >= size and j >= size and
region_count((i-size, j-size), (i, j)) == size*size:
min_squares[i][j] = min(min_squares[i][j],
min_squares[i-size-1][j] +
min_squares[i][j-size-1] -
min_squares[i-size-1][j-size-1] +
1)
In order to reconstruct the tiling needed to get the calculated minimum, we use an auxiliary size_used[r][c] array which we use to keep track of the size of square placed at (r, c). From this we can recursively reconstruct the tiling:
function reconstruct(i, j):
if i < 0 or j < 0:
return
place square of size size_used[i][j] at (i-size_used[i][j]+1, j-size_used[i][j]+1)
reconstruct(i-size_used[i][j], j)
reconstruct(i, j-size_used[i][j])
You might want to look at Optimal way for partitioning a cell based shape into a minimal amount of rectangles - if I understood correctly, this is the same problem but for rectangles instead of squares.