MATLAB: How to 'color in' pixels of a grayscale image sequence? - matlab

Supposing I have the linear indices of the pixels which I would like to 'color in'.
If I wanted to set all of those pixels to some specific value in my grayscale image sequence, I could do this:
gryscl_imSeq(LinearPixIndx) = 0.7;
edit: where 'LinearPixIndx' is a p-element vector containing the linear indices of the pixels in the image sequence.
If however, I want to introduce some color, I would first need to convert my grayscale image sequence into an m x n x 3 x p matrix, which I could do like this:
RGBvideo = reshape(repmat(reshape(gryscl_imSeq,[],size(gryscl_imSeq,3)),3,1),...
[size(gryscl_imSeq,1) size(gryscl_imSeq,2) 3 size(gryscl_imSeq,3)]);
If somebody could tell me how to convert my grayscale linear pixels indices into corresponding indices for the RGBvideo I would really appreciate it.
Or if there is a better way to go about what I'm trying to do, I would be very grateful for any suggestions.
Thanks in Advance,
N

The question isn't really clear, but I guess I understand what you want. Here's one way to do it.
First I think there's a slightly more elegant way to convert from grayscale to RGB:
% determine image sequence dimensions
[m, n, N] = size(gryscl_imSeq);
% expand to RGB
rgb_imSeq = reshape(gryscl_imSeq, [m, n, 1, N]);
rgb_imSeq = repmat(rgb_imSeq, [1, 1, 3, 1]);
After that, in order to be able to apply your linear indices to all color channels and all frames, you need to explicitly linearize the pixel index by reshaping. Then you can color the pixels, and transform back into the form width x height x color channels x frames:
% linearize image dimensions
rgb_imSeq = reshape(rgb_imSeq, [m * n, 3, N]);
% color pixels
rgb_imSeq(LinearPixIndx, :, :) = repmat([1 0 0], [numel(LinearPixIndx), 1, N]);
% original shape
rgb_imSeq = reshape(rgb_imSeq, [m, n, 3, N]);
Here [1 0 0] is the RGB representation of the color you want to use, in this case red.

Related

Functions that calculates a filter mask of size NXN and applies it to an input image I using conv2() function in Matlab

I am trying to write a function to create a filter mask of size NXN and then apply it to an image read in. Here is my attempt...
function Iout = noiseReduction(I, N)
image = imread(I);
figure(3)
subplot(2,1,1), imshow(image), title('Original Image', 'FontSize', 15);
mask = ones(3,3) * N;
Iout = conv2(image, mask);
subplot(2,1,2), imshow(uint8(Iout)), title('Blurred Image', 'FontSize', 15);
end
However, when I run the function I don't get any output in Blurred Image I just get a blank square. Can anyone help me figure out what is wrong with this? Any help would be fantastic.
mask = ones(3,3) * N;
This is not a NxN filter, but a 3x3 filter where each element has a value of N.
By convolving with such a filter, you obtain an image with very large values. You later cast this to uint8, clamping all values to 255. Hence the image looks all white.
Instead, define your kernel as:
mask = ones(N,N) / N^2;
Now mask is NxN and sums to 1, meaning that the output will remain in the same range as the input.

Working with an specific region generated by BoundingBox

I have n regions generated by regionprops with 'BoundingBox' and 'Image' properties. I saved the data ([x, y, Δx, Δy]) from a specific region (14 for example) to bb1 that I want to work on but first I need to understand the following code:
bb1=floor( Ic(14,1).BoundingBox );
I1bb1=I1( bb1(2):bb1(2)+bb1(4)-1 , bb1(1):bb1(1)+bb1(3)-1 ,:);
After that, also I want to understand the next code that it is from the same example:
I2=I1bb1.*repmat( Ic(BB,1).Image , [1 1 3]);
Where Ic contains n regions generated by BoundingBox
You have a 3D variable I1 (I guess RGB image) and you wish to crop the boundingbox Ic(14,1).BoundingBox from it. That is, have a smaller 3D array that corresponds to the pixels inside the bounding box in image I1. To do this cropping you have these commands:
bb1=floor( Ic(14,1).BoundingBox );
First, you make sure the values [x, y, w, h] of the bounding box are integers and not sub-pixels so that you can use these values for indexing. Then, you can index into I1 with the bounding box:
I1bb1=I1( bb1(2):bb1(2)+bb1(4)-1 , bb1(1):bb1(1)+bb1(3)-1 ,:);
For the rows of I1bb1 you take the rows from bb1(2) (y value) to y+w-1 which is bb1(2)+bb1(4)-1. Same for the columns from x to x+h-1.
For the third line of code, you have the property Ic(14,1).Image. This property is
Returns a binary image (logical) of the same size as the bounding box of the region. The on pixels correspond to the region, and all other pixels are off.
Now you want I2 to be the same size as the bounding box, but all pixels in the boundingbox not belonging to the object are set to [0 0 0] (all RGB values zero). Thus you convert Ic(14,1).Image from 2D binary mask to a 3D mask over three channels:
repmat( Ic(BB,1).Image , [1 1 3])
Finally you element-wise multiply the "inflated" mask with the cropped image I1bb1:
I2=I1bb1.*repmat( Ic(BB,1).Image , [1 1 3]);
You can achieve the same results with slightly more readable code:
Ibb1 = imcrop( I1, bb1 ); %// crop a bounding box from image
I2 = bsxfun( #times, Ibb1, Ic(14,1).Image ); %// no need for repmat

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);

Get matrix with colors of colomap figure

I have generated a heatmap from a matrix of values and applied a colormap on it. Is there a way for me to create an m-by-3 matrix of the colors of each square segment?
My understanding is that you have a matrix of values (m-by-n) which you colour using a colour map and you want to get the 3D (m-by-n-by-3) matrix that is the RBG image of this coloured matrix. In that case try:
%//C is your data
C = randn(m,n);
%//d is the number of discrete colour in your colormap and map is your colormap itself.
d=4;
map = jet(d);
%//Normalize C to index map, i.e. make values of C range from 1 to d
C_norm = (C - min(C(:)))./(max(C(:)) - min(C(:))); %//Normalize to btw [0,1]
C_discrete = ceil(C_norm*(d-1)+1); %//Normalize to btw [1,d]
%//Index in map using linearized (i.e. m*n-by-1 vector) version of C
C_mapped = map(C_discrete(:),:);
%//Reshape to m-by-n-by-3
C_RGBreshape(permute(C_mapped, [1, 3, 2]), m, n, 3);
You mean to create a matrix with the colormap? Normally you do it the other way around. Try
cmap = jet(64);
colormap(cmap);
This assigns the colormap to cmap as a matrix and then assigns it to th axes. I also think that the colormap is an axes property and can be accessed through the set and get functions. Also you may not want to use the jet colormap but any colormap can of course be used

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]);