How to reshape 3D derivatives matrices to 3x3xn matrix? - matlab

I have 3D derivatives of image Dxx,Dyx,Dyy,Dxz,Dzz,Dzy each of 513x512x200
where 512x512 are the images dimensions of 200 images.
Now i want to use eig3 that can take 3x3xn matrix
How can i reshape these matrices to a 3x3xn matrix ?
EDIT
n is supposed to be the number of voxels and the 3x3 matrix should be like
Dxx Dxy Dxz
Dyx Dyy Dyz
Daz Dzy Dzz

The manipulation of the matrices can be achieved by using 'permute' and 'reshape' as follows.
% say you saved your 2nd derivative 3D image as 'Ds'
Ds = [Dxx(:) Dxy(:) Dxz(:) Dyz(:) Dyy(:) Dyz(:) Dzz(:) Dzy(:) Dzz(:)];
% permute
Ds = permute(Ds,[2 1]);
% reshape
n = numel(Dxx);
Ds = reshape(Ds,[3 3 n]);
Enjoy!

Maybe you were looking for something like this -
%%// M and N are the dims of each image and P is the count of images.
%%// Please not that for 3x3 block processing, you would need to make sure that
%%// the width of images are divisble by 3; if they are not, consider cropping or padding.
IN = some_MxNxP_data;
%%// In-code cropping, as mentioned earlier
IN = IN(:,1:3*floor(size(IN,2)/3),:);
%%// Final output would be a complex matrix of size Mx(N/3)xP
OUT = zeros(size(IN,1),size(IN,2)/3);
%%// Main calculation part that uses block processing creating 3x3 blocks and using eig3 on each of them
for k = 1:size(IN,3)
fun1 = #(block_struct) eig3(block_struct.data);
OUT(:,:,k) = blockproc(double(IN(:,:,k)),[3 3],fun1);
end
Edit 1
Code
M = 7; %%// Image height, which must be replaced by actual data, 512 in your case
N = 7; %%// Image width, which must be replaced by actual data, 512 in your case
P = 5; %%// Number of images, which must be replaced by actual data, 200 in your case
%%// Your Dxx,Dyx... data, which is created randomly here, for demo
Dxx= rand(M,N,P);
Dyx= rand(M,N,P);
Daz= rand(M,N,P);
Dxy= rand(M,N,P);
Dyy= rand(M,N,P);
Dzy= rand(M,N,P);
Dxz= rand(M,N,P);
Dyz= rand(M,N,P);
Dzz= rand(M,N,P);
voxel_mat = zeros(3,3,M,N,P);
eig_mat = zeros(M,N,3);
for k0 = 1:P
for k1 = 1:M
for k2 = 1:N
voxel_mat(:,:,k1,k2,k0) = [Dxx(k1,k2,k0) Dxy(k1,k2,k0) Dxz(k1,k2,k0); ...
Dyx(k1,k2,k0) Dyy(k1,k2,k0) Dyz(k1,k2,k0); ...
Daz(k1,k2,k0) Dzy(k1,k2,k0) Dzz(k1,k2,k0)];
eig_mat(k1,k2,:,k0) = eig3(voxel_mat(:,:,k1,k2,k0));
end
end
end

Related

Unintended infinite loop with `imshow`

for i = [I, J, K];
imshow(i);
end
I, J, K are 16-bit images.
The script keeps trying to pump out the images (but doesn't) and gets into an infinite loop.
Is there something I'm missing?
You can store multiple images in a matrix if they have the same sizes.
However, You should store the images in a cell if they have different sizes. This method is less messier because you don't need to worry about how to extract them later.
define a cell with the size equal to the number of images.
numImages = 3;
Images = cell(1,numImage);
Store an image I into a cell:
Images{1,1} = I;
Now go over the images and show them
for ii = 1:3
imshow(Images{1,ii});
end
Example:
I = imread('cameraman.tif');
J = imread('peppers.png');
K = imread('snowflakes.png');
Images = cell(1,3);
Images{1,1} = I;
Images{1,2} = J;
Images{1,3} = K;
for ii=1:numel(Images)
figure;imshow(Images{1,ii});
end
For better understanding as to which point exactly you are missing/what is happening here: Using square brackets works like a concatenation here. So the line
i = [I, J, K] % separated with commas or spaces for horzcat
i = [I; J; K] % separated with semi-colons for vertcat
does the same as horzcat or vertcat:
i = horzcat(I, J, K);
i = vertcat(I, J, K);
Let's say I, J, K are 64x64 gray valued images. A (horizontal) concatenation will create a 64x192 matrix. The for loop will go through your matrix column-wise, which means it will extract a 64x1 vector 192-times (or much more often for larger images, which might feel like "infinite"). Displaying only a vector with imshow() won't show anything.
As already pointed out, using cells is a more flexible way to store images. When using arrays you have to handle each dimension (and this only works if your images are equal in size):
sizeImage = size(I); % assume all img are same size (as I)
numImages = 3; % needed for allocating array
% init array for imgs and fill images into array: e.g. 64x64x3
imageArray = zeros([sizeImage numImages]);
imageArray(:,:,1) = I; % :,: selects all elements of a dimension
imageArray(:,:,2) = J;
imageArray(:,:,3) = K;
for n = 1:numImages % iterate over image index
figure; imshow(imageArray(:,:,n)); % n = 1, 2 ... , numImages
end % is used for position in imageArray
Using the colon : when accessing arrays/cells selects all elements of a dimension. E.g. imageArray(:,:,n) will select all elements of first and second dimension, corresponding to a 64x64 image. For RGB images an array with 3 images will be 64x64x3x3 and you'll have to use imageArray(:,:,:,n) to select all three color channels.
Note that using for i = img_array won't work, as this will give vectors again.
E.g. for img_array: 64x64x5 (five 64x64 gray-valued images), this will iterate over all but one dimensions (and assign the remaining dim to i): img_array(:,1,1), img_array(:,2,1), img_array(:,3,1), ..., img_array(:,1,2), img_array(:,2,2) ..., img_array(:,64,5) and will again produce 64*3 = 192 vectors for i.
As was already pointed out, if you have variable image sizes, using cell arrays is the way. You may want to consult: Difference between cell and matrix in matlab?

Sample 1D vectors from 3D array using a vector of points

I have a n channel image and I have a 100x2 matrix of points (in my case n is 20 but perhaps it is more clear to think of this as a 3 channel image). I need to sample the image at each point and get an nx100 array of these image points.
I know how to do this with a for loop:
for j = 1:100
samples(j,:) = image(points(j,1),points(j,2),:);
end
How would I vectorize this? I have tried
samples = image(points);
but this gives 200 samples of 20 channels. And if I try
samples = image(points,:);
this gives me 200 samples of 4800 channels. Even
samples = image(points(:,1),points(:,2));
gives me 100 x 100 samples of 20 (one for each possible combination of x in X and y in Y)
A concise way to do this would be to reshape your image so that you force your image that was [nRows, nCols, nChannels] to be [nRows*nCols, nChannels]. Then you can convert your points array into a linear index (using sub2ind) which will correspond to the new "combined" row index. Then to grab all channels, you can simply use the colon operator (:) for the second dimension which now represents the channels.
% Determine the new row index that will correspond to each point after we reshape it
sz = size(image);
inds = sub2ind(sz([1, 2]), points(:,2), points(:,1));
% Do the reshaping (i.e. flatten the first two dimensions)
reshaped_image = reshape(image, [], size(image, 3));
% Grab the pixels (rows) that we care about for all channels
newimage = reshaped_image(inds, :);
size(newimage)
100 20
Now you have the image sampled at the points you wanted for all channels.

how to take an average of a 2x2 pixel block?

I have an image and I have to take the average of the color of 2x2 pixel.
take the average color of a 2x2 pixel block, then compute the distance between the colors in the image and the colors available for our use.
I have no idea what taking the average of 2x2 pixel block means. How to solve this?
Thank you.
You can process non-overlapping blocks of an image using blockproc
Im = imread('coins.png'); %// example image
fun = #(block_struct) mean( block_struct.data(:) ); %// anonymous function to get average of a block
B = blockproc(Im,[2 2],fun); %// process 2 by 2 blocks
imshow(B,[]); %// show resulting image
One other method I can suggest is to use combination of colfilt with the 'sliding' flag and mean as the function to operate on. The 'distinct' flag is what you actually need to use, but if you see the conversation between myself and #eigenchris, we couldn't get it to work. Still, eigenchris has shown that this is 300x faster than blockproc.
Therefore, assuming your image is stored in im, you can simply do:
out = uint8(colfilt(im, [2 2], 'sliding', #mean));
out2 = out(1:2:end,1:2:end);
The reason why you would need to subsample the results is because when we apply a sliding option, you have overlapping blocks processing the image at a time. Because you want distinct blocks, you only need 1/4 of the image because you have decomposed the image into 2 x 2 blocks. Within a 2 x 2 block, if you did the sliding option, you would have three other results that are not required, and so doing the subsampling above by a factor of two eliminates those three other blocks that give results.
Note that you'll need to cast the result as the output will be of type double.
Going with the discussion between myself and eigenchris, you can replace colfilt with the canonical imfilter to replicate the first line of the above code. I managed to get an 8x speedup on my machine when comparing the two together. Therefore:
out = imfilter(im, [0.25 0.25; 0.25 0.25], 'replicate');
out2 = out(1:2:end,1:2:end);
In terms of speedup, I wrapped each call in an anonymous function, then used timeit to time the functions:
>> f = #() uint8(colfilt(im, [2 2], 'sliding', #mean));
>> g = #() imfilter(im, [0.25 0.25; 0.25 0.25], 'replicate');
>> T = timeit(f);
>> T2 = timeit(g);
>> T/T2
ans =
7.5421
As you can see, there is roughly a 8x speedup over colfilt... most likely because it's calling im2col and col2im under the hood.
Using loops: (another method, just for knowing)
A = imread('cameraman.tif');
i = 1; j = 1;
[rows, cols] = size(A);
C(rows/2,cols/2) = 0;
for x = 1:2:rows
for y = 1:2:cols
block = [A(x,y),A(x+1,y),A(x,y+1),A(x+1,y+1)];
C(i,j) = mean(block(:));
j = j+1;
end
i = i+1;
j = 1;
end
C = uint8(C);
figure;
imshow(A); %// show original image
figure;
imshow(C); %// show resulting image

How can thin horizontal lines be added between each row in a grayscale image?

I need to create an nth-order Hadamard matrix, row double it, within each row randomly permute the elements of the matrix, and then display it. So far, I have accomplished all of these things. What I end up with when I imshow(matrix) is a nice picture of black and white boxes. But I haven't figured out how to insert a fine line to divide each row. I can create something like the first image on the left, but not the image on the right (these are Figures 1 and 2 from this paper)
Any help or comments would be thoroughly appreciated.
I've found using vector approaches (e.g., patch and rectangle) for this sort of problem unnecessarily challenging. I think that it's more straightforward to build a new image. This avoids floating-point rounding issues and other things that crop up with vector graphics. My solution below relies on some functions in the Image Processing Toolbox, but is simple and fast:
% Create data similarly to #TryHard
H = hadamard(48);
C = (1+[H;-H])/2;
rng(0); % Set seed
C(:) = C(randperm(numel(C))); % For demo, just permute all values, not rows
% Scale image and lines
scl = 10; % Amount to vertically scale each row
pad = 2; % Number of pixels to add between each row
C = imresize(C,scl,'nearest');
C = blockproc(C,[scl size(C,2)],#(x)[x.data;zeros(pad,size(C,2))]);
C = C(1:end-pad,:); % Remove last line added
% Dispay image
imshow(C)
This results in an image like this
The scl and pad parameters can be easily adjusted to obtain different sizes and relative sizes. You can call imresize(...,'nearest') again after adding the lines to further scale the image if desired. The blocproc line could potentially be made more efficient with various options (see the help). It could also be replaced by calls to im2col and col2im, which possibly could be faster, if messier.
I did not try the code, but I think that something like that should work:
sizeOfACube = 6;
numberOfRows = 47;
RGB = imread('image.png');
RGB = imresize(A, [(numRows+numberOfRows) numCols]);
for i=1:1:NumberOfRows
RGB(i*6,:,:) = 0;
end
imagesc(RGB);
imwrite(RGB,'newImage.png');
with:
sizeOfAcube the size of one cube on the QRcode.
numRows and numCols the number of Rows and Column of the original image.
One solution is to use patches, for instance as follows:
% set up example array
xl = 24; yl = xl;
[X Y] = find(hadamard(xl)==1);
% generate figure
figure, hold on
for ii=1:length(X)
patch(X(ii) + [0 0 1 1],Y(ii) + [0.1 0.9 0.9 0.1],[1 1 1],'Edgecolor',[1 1 1])
end
axis([0 xl+1 0 yl+1])
axis('square')
The patch command patch(x,y, color) accepts the vertices of the polygon element as x and y. In this example you can modify the term [0.1 0.9 0.9 0.1] to set the thickness of the bounding black line.
This generates
Edited
For the particular instance provided by the OP:
H=Hadamard(48); %# now to row-double the matrix
A=(1+H)/2;
B=(1-H)/2;
C=[A; B]; %# the code below randomly permutes elements within the rows of the matrix
[nRows,nCols] = size(C);
[junk,idx] = sort(rand(nRows,nCols),2); %# convert column indices into linear indices
idx = (idx-1)*nRows + ndgrid(1:nRows,1:nCols); %# rearrange whatever matrix
E = C;
E(:) = E(idx);
[X Y] = find(logical(E));
xl = length(X);
yl = length(Y);
figure, hold on
for ii=1:xl
rectangle('Position',[X(ii) Y(ii)+.2 1 0.8],'facecolor',[1 1 1],'edgecolor',[1 1 1])
end
axis([0 max(X)+1 0 max(Y)+1])
axis('square')
set(gca,'color',[0 0 0])
set(gca,'XTickLabel',[],'YTickLabel',[],'XTick',[],'YTick',[])
This example uses rectangle instead of patch to generate sharp corners.
The image:

please help me Assignment has more non-singleton rhs dimensions than non-singleton

I have the following error in my code
Assignment has more non-singleton rhs
dimensions than non-singleton
This is the code:
string =['d:\face\face\ffw' int2str(r) '_' int2str(Sel(nSelRow,t)) '.bmp'];
A = imread(string);
B = im2double(A);
Train_Dat(:,:,s)=B;
Update 1:
When I updated the code we got new error in the next row
my code
for r=1:Class_Num
for t=1:Class_Train_Num
%string=['e:\face_lib\feret_80\ff' int2str(r) '_' int2str(t) '.tif'];
string =['d:\face\face\ffw' int2str(r) '_' int2str(Sel(nSelRow,t)) '.bmp'];
A=imread(string);
B=im2double(A);
Train_Dat(:,:,:,s)=B;
Train_Dat_Vector(:,s)=B(:); %here new error Subscripted assignment dimension mismatch.
s=s+1;
end
Update 2:
my define for
nImgW = 40;
nImgH = 40;
nImgSize = nImgW*nImgH;
Train_Dat_Vector = zeros( nImgSize, Train_Num );
A=imread(string);
B=im2double(A);
Train_Dat(:,:,:,s)=B;
Train_Dat_Vector(:,s)=B(:);%here i want convert matrix to 40x40,Train_Num
s=s+1;
I think the problem is that B is most likely a 3-D RGB image, and you're trying to assign it to a single 2-D plane of your 3-D matrix Train_Dat. If you're trying to collect a set of 3-D images to use as training data, you will have to make Train_Dat either a 4-D matrix (if all of your images have the exact same dimensions) or a cell array (with one image per cell):
Example #1: a 4-D matrix...
nRows = 100; %# The number of rows in the images
nCols = 100; %# The number of columns in the images
nDepth = 3; %# The depth of the images (3 color planes for RGB images)
nImages = 5; %# The number of images you will use
Train_Dat = zeros(nRows,nCols,nDepth,nImages); %# Initialize to zeros
Train_Dat(:,:,:,1) = B; %# Assign B as the first image
If you want to use this option, but all of your images are not the same size, you will have to resize them all to a given size. One way to do this, if you have the Image Processing Toolbox, is to use the function IMRESIZE:
newSize = [40 40]; %# The new size the image will be
C = imresize(B,newSize); %# Resize image B
If you don't have access to the Image Processing Toolbox, one alternative is to use the function INTERP2 to resize your image. Here's one example of resizing a 3-D RGB image of type UINT8:
B = double(B); %# Convert B to double (needed to use INTERP2)
[nRows,nCols,nDepth] = size(B); %# Get the old image size
C = zeros(40,40,3,'uint8'); %# Initialize the new 3-D 40-by-40 uint8 image
xi = linspace(1,nCols,40); %# Create a down-sampled set of x points
yi = linspace(1,nRows,40); %# Create a down-sampled set of y points
[X,Y] = meshgrid(xi,yi); %# Create 40-by-40 grids of x and y points
C(:,:,1) = interp2(B(:,:,1),X,Y,'spline'); %# Interpolate the red color plane
C(:,:,2) = interp2(B(:,:,2),X,Y,'spline'); %# Interpolate the green color plane
C(:,:,3) = interp2(B(:,:,3),X,Y,'spline'); %# Interpolate the blue color plane
The image C will now be a down-sampled 40-by-40 version of B.
Example #2: a cell array...
nImages = 5; %# The number of images you will use
Train_Dat = cell(1,nImages); %# Initialize the cell array
Train_Dat{1} = B; %# Assign B as the first image
In this case, the images you add to each cell can be different sizes and types, so no resizing is needed.