Matlab padarray function - matlab

I have an image of size 350X450. I'm trying to pad with zeros the matrix which represents the image in a way that I'll have the original matrix in the center of the new padded matrix with a new dimensions of 700X900. Here is what I want to do:
I'm trying to implement that using padarray function:
(Suppose w is the desired width, h is the desired height and im is the image(matrix))
new_image=paddarray(im, [0.5*w 0.5*h]);
I don't get the desired result. What am I missing? Is there a better way to do this?

Your syntax is right, you should set w = ceil((700-350)/2) and h = ceil((900-450)/2).

As the HELP entry says:
B = padarray(A,PADSIZE)
pads array A with PADSIZE(k) number of zeros along the k-th dimension of A.
padarray([1 2; 3 4],[1 1]) %makes a 4x4 matrix
You don't want to pad with w and h, you want to pad with
(wDesired - wCurrent)/2 %floor or ceil, depending on your mood.

Related

How can I modify a set of vectors to have the same size?

i'm trying to extract HOG_features for mathematical symbols classification (i will use SVM classifier). I get a 1xn vector then i have to put all the vectors in a single matrix. The problem is that the size of the feature vector is different for each image so I can't concatenate them.
Is there a way to make all vectors having the same size ?
Thank you in advance.
Here is the code:
rep1 = 'D:\mémoire MASTER\data';
ext = '*.tif' ;
chemin = fullfile(rep1, ext);
list = dir(chemin);
for i=1:length(list)
I = imread(fullfile(rep1, list(i).name), ext(3:end));
if size(I,3)==3 % RGB image
I = rgb2gray(I);
end
I1 = imbinarize(I);
% Extract HOG features data
HOG_feat = extractHOGFeatures(I1,'CellSize', [2 2]);
HOG_feat1 = HOG_feat';
end
You can pad each one with zeros to be as long as the longest one:
e.g. to put two vectors, v1 and v2, into a matrix M:
M = zeros(2,max(length(v1),length(v2)));
M(1,1:length(v1)) = v1;
M(2,1:length(v2)) = v2;
You have the problem that all your vectors are a different size. Instead of trying to coerce them to be the sesame size by zero-padding or interpolating (both I think are bad ideas), change your computation so that the length of the output vector does not depend on the size of the image.
This is your current code:
HOG_feat = extractHOGFeatures(I1,'CellSize', [2 2]);
% ^^^
% the image is split in cells of 2x2 pixels
2x2 cells are way too small for this method anyway. You could instead divide your image into a set number of cells, say 100 cells:
cellSize = ceil(size(I1)/10);
HOG_feat = extractHOGFeatures(I1,'CellSize', cellSize);
(I’m using ceil in the division because I figure it’s necessary to have an integer size. But I’m not sure whether ceil or floor or round is needed here, and I don’t have access to this function to test it. A bit of trial and error should show which method gives consistent output size.)

Zero pad image before FFT in MATLAB

I have an image of size 64x64 and I should take its Fourier transform. I should pad with zeros to the right and bottom of the original image to make it 128x128, and then again take its Fourier transform. And then repeat this procedure for 256x256 and 512x512 sized images and find a relation between the final Fourier transforms.
Can anyone tell me how should I do this? I don't know how to zero pad the image to get a double sized image with half zeros.
There are multiple ways to zero pad. You can just create an array using zeros of double the size, and then put in the image in the indices on the top left:
A = imread('coins.png');
[s1, s2] = size(A);
B = zeros(s1*2, s2*2, class(A));
B(1:s1,1:s2) = A;
To make sure that the new array B is of the same type as the original image A, I used class(A).
Alternatively you can use padarray. Specify the number of elements to pad in each direction, what to pad, and where to put it ('post').
C = padarray(A, [s1 s2], 0, 'post');

Matlab: trouble with taking derivative of image?

So I need to take the derivative of an image in the x-direction for this assignment, with the goal of getting some form of gradient. My thought is to use the diff(command) on each row of the image and then apply a Gaussian filter. I haven't started the second part because the first is giving me trouble. In attempting to get the x-derivative I have:
origImage = imread('TightRope.png');
for h = 1:3 %%h represents color channel
for i = size(origImage,1)
newImage(i,:,h) = diff(origImage(i,:,h)); %%take derivative of row and translate to new row
end
end
The issue is somewhere along the way I get the error 'Subscripted assignment dimension mismatch.'.
Error in Untitled2 (line 14)
newImage(i,:,h) = diff(origImage(i,:,h));
Does anyone have any ideas on why that might be happening and if my approach is correct for getting the gradient/gaussian derivative?
Why not use fspecial along with imfilter instead?
figure;
I = imread('cameraman.tif');
subplot 131; imshow(I); title('original')
h = fspecial('prewitt');
derivative = imfilter(I,h','replicate'); %'
subplot 132; imshow(derivative); title('derivative')
hsize = 5;
sigma = 1;
h = fspecial('gaussian', hsize, sigma) ;
gaussian = imfilter(derivative,h','replicate'); %'
subplot 133; imshow(gaussian); title('derivative + gaussian')
The result is the following one:
If your goal is to use diff to generate the derivative rather than to create a loop, you can just tell diff to give you the derivative in the x-direction (along dimension 2):
newImage = diff(double(origImage), 1, 2);
The 1 is for the first derivative and 2 is for the derivative along the second dimension. See diff.
As #rayryeng mentions in his answer, it's important to cast the image as double.
Given a N element vector, diff returns a N-1 length vector, so the reason why you are getting an alignment mismatch is because you are trying to assign the output of diff into an incorrect number of slots. Concretely, supposing that N is the total number of columns, you are using diff on a 1 X N vector which thus returns a 1 x (N - 1) vector and you are trying to assign this output as a single row into the output image which is expected to be 1 x N. The missing element is causing the alignment mismatch. diff works by taking pairs of elements in the vector and subtracting them to produce new elements, thus the reason why there is one element missing in the final output.
If you want to get your code working, one way is to pad each row of the image or signal vector with an additional zero (for example) as input into diff. Something like this could work. Take note that I'll be converting your image to double to allow the derivative to take on negative values:
origImage = imread('...'); %// Place path to image here and read in
origImage = im2double(origImage); %// Change - Convert to double precision
newImage = zeros(size(origImage)); %// Change - Create blank new image and populate each row per channel manually
for h = 1:3 %%h represents color channel
for ii = 1:size(origImage,1) %// Change - fixed for loop iteration
newImage(ii,:,h) = diff([0 origImage(ii,:,h)]); %// Change
end
end
Take note that your for loop was incorrect since it didn't go over every row... just the last row.
When I use the onion.png image that's part of the image processing toolbox:
...and when I run this code, I get this image using imshow(newImage,[]);:
Take note that the difference filter was applied to each channel individually and I changed the intensities per channel so that the smallest value gets mapped to 0 and the largest value gets mapped to 1. How you can interpret this image is that any areasthat have a non-black colour have some non-zero differences and hence there is some activity going on in those areas and any areas that have a dark / black colour means that there is no activity going on in those areas. Take note that we applied a horizontal filter, so if you wanted to do this vertically, you'd simply repeat the behaviour but apply this column-wise instead of row-wise as you did above.

MATLAB image patches around multiple coordinates (in vectors) without loops [duplicate]

I need to extract image patches of size s x s x 3 around specified 2D locations from an image (3 channels).
How can I do this efficiently without a for loop? I know I can extract one patch around (x,y) location as:
apatch = I(y-s/2:y+s/2, x-s/2:x+s/2, :)
How can I do this for many patches? I know I can use MATLAB's function blockproc but I can't specify the locations.
You can use im2col from the image processing toolbox to transform each pixel neighbourhood into a single column. The pixel neighbourhoods are selected such that each block is chose on a column-basis, which means that the blocks are constructed by traversing down the rows first, then proceeding to the next column and getting the neighbourhoods there.
You call im2col this way:
B = im2col(A, [M N]);
I'm assuming you'll want sliding / overlapping neighbourhoods and not distinct neighbourhoods, which are what is normally used when performing any kind of image filtering. A is your image and you want to find M x N pixel neighbourhoods transformed as columns. B would be the output where each neighbourhood is a single column and horizontally-tiled together. However, you'll probably want to handle the case where you want to grab pixel neighbourhoods along the borders of the image. In this case, you'll want to pad the image first. We're going to assume that M and N are odd to allow the padding to be easier. Specifically, you want to be sure that there are floor(M/2) rows padded on top of the image as well as the bottom as well as floor(N/2) columns padded to the left of the image as well as the right. As such, we should pad A first by using padarray. Let's assume that the border pixels will be replicated, which means that the padded rows and columns will simply be those grabbed from the top or bottom row, or the left and right column, depending on where we need to pad. Therefore:
Apad = padarray(A, floor([M N]/2), 'replicate');
For the next part, if you want to choose specify neighbourhoods, you can use sub2ind to convert your 2D co-ordinates into linear indices so you can select the right columns to get the right pixel blocks. However, because you have a colour image, you'll want to perform im2col on each colour channel. Unfortunately, im2col only works on grayscale images, and so you'd have to repeat this for each channel in your image.
As such, to get ready for patch sampling, do something like this:
B = arrayfun(#(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
The above code will create a 3D version of im2col, where each 3D slice would be what im2col produces for each colour channel. Now, we can use sub2ind to convert your (x,y) co-ordinates into linear indices so that we can choose which pixel neighbourhoods we want. Therefore, assuming your positions are stored in vectors x and y, you would do something like this:
%// Generate linear indices
ind = sub2ind([size(A,1) size(A,2)], y, x);
%// Select neighbourhoods
%// Should be shaped as a MN x len(ind) x 3 matrix
neigh = B(:,ind,:);
%// Create cell arrays for each patch
patches = arrayfun(#(x) reshape(B(:,x,:), [M N 3]), 1:numel(ind), 'uni', 0);
patches will be a cell array where each element contains your desired patch at each location of (x,y) that you specify. Therefore, patches{1} would be the patch located at (x(1), y(1)), patches{2} would be the patch located at (x(2), y(2)), etc. For your copying and pasting pleasure, this is what we have:
%// Define image, M and N here
%//...
%//...
Apad = padarray(A, floor([M N]/2), 'replicate');
B = arrayfun(#(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
ind = sub2ind([size(A,1) size(A,2)], y, x);
neigh = B(:,ind,:);
patches = arrayfun(#(x) reshape(neigh(:,x,:), [M N 3]), 1:numel(ind), 'uni', 0);
As unexpected as this may seem, but for me the naive for-loop is actually the fastest. This might depend on your version of MATLAB though, as with newer versions they keep on improving the JIT compiler.
Common data:
A = rand(30, 30, 3); % Image
I = [5,2,3,21,24]; % I = y
J = [3,7,5,20,22]; % J = x
s = 3; % Block size
Naive approach: (faster than im2col and arrayfun!)
Patches = cell(size(I));
steps = -(s-1)/2:(s-1)/2;
for k = 1:numel(Patches);
Patches{k} = A(I(k)+steps, ...
J(k)+steps, ...
:);
end
Approach using arrayfun: (slower than the loop)
steps = -(s-1)/2:(s-1)/2;
Patches = arrayfun(#(ii,jj) A(ii+steps,jj+steps,:), I, J, 'UniformOutput', false);

Is there an efficient way to pad a matrix with zeros on all sides?

I'm performing texture synthesis on images using the Efros and Leung Algorithm. My goal is to grow the size of my current textured image and, to do it, I'd like to pad the current image matrix with zeros on all sides.
My current plan given an original image matrix of size MxN and a desired growth size of P:
(1) Create a target matrix of size (M+2P)x(N+2P)
(2) Set the value of target(i+P,j+P) = original(i,j)
(3) Run Efros and Leung
Is there a way I can eliminate (1) and (2) and just operate on the original image to pad it in all directions with P zeros?
If you have access to the Image Processing Toolbox, you can use the function PADARRAY:
imgPadded = padarray(img, [p p], 0, 'both');
Otherwise you can simply use matrix indexing:
sz = size(img);
imgPadded = zeros([sz(1:2)+2*p size(img,3)], class(img));
imgPadded((1:sz(1))+p, (1:sz(2))+p, :) = img;
This should work for both grayscale and RGB images.
>> y = [zeros(P,N+2*P) ; [zeros(M,P), x, zeros(M,P)] ; zeros(P,N+2*P)];
where x is the original image matrix and y is the output should work. If the matrix has 3 planes, adjust to:
>> y = [zeros(P,N+2*P,3) ; [zeros(M,P,3), x, zeros(M,P,3)] ; zeros(P,N+2*P,3)];
Use padarray:
y = padarray(x, [P P]);