How to create a 2D image by rotating 1D vector of numbers around its center element? - matlab

I have 1D vector of numbers which represents a center cut of a circular symmetric object. The vector itself is symmetric around its center element. I want to create in MATLAB a 2D image of the original object by rotating the 1D vector around its center element.
I tried the following code (with a dummy original vector of numbers) , but the center cut I get from the generated 2D image does not match the original 1D vector, as can be seen if you run the code.
I'll appreciate any help !!!
close all; clc
my1D_vector=[ zeros(1,20) ones(1,15) zeros(1,20)]; % original vector
len=length(my1D_vector);
img=zeros(len, len);
thetaVec=0:0.1:179.9; % angles through which to rotate the original vector
numRotations=length(thetaVec);
% the coordinates of the original vector and the generated 2D image:
x=(1:len)-(floor(len/2)+1);
y=x;
[X,Y]=meshgrid(x,y);
for ind_rotations=1:numRotations
theta=pi/180*thetaVec(ind_rotations);
t_theta=X.*cos(theta)+Y.*sin(theta);
cutContrib=interp1(x , my1D_vector , t_theta(:),'linear');
img=img+reshape(cutContrib,len,len);
end
img=img/numRotations;
figure('name','original vector');plot(x,my1D_vector,'b.-')
figure('name','generated 2D image'); imagesc(x,y,img); colormap(gray) ;
figure('name','comparison between the original vector and a center cut from the generated 2D image');
plot(x,my1D_vector,'b.-')
hold on
plot(x,img(find(x==0),:),'m.-')
legend('original 1D vector','a center cut from the generated 2D image')

I didn't follow your code but how about this:
V = [ zeros(1,20) ones(1,15) zeros(1,20)]; % Any symmetrical vector
n = floor(numel(V)/2);
r = [n:-1:0, 1:n]; % A vector of distance (measured in pixels) from the center of vector V to each element of V
% Now find the distance of each element of a square 2D matrix from it's centre. #(x,y)(sqrt(x.^2+y.^2)) is just the Euclidean distance function.
ri = bsxfun(#(x,y)(sqrt(x.^2+y.^2)),r,r');
% Now use those distance matrices to interpole V
img = interp1(r(1:n+1),V(1:n+1),ri);
% The corners will contain NaN because they are further than any point we had data for so we get rid of the NaNs
img(isnan(img)) = 0; % or instead of zero, whatever you want your background colour to be
So instead of interpolating on the angle, I interpolate on the radius. So r represents a vector of the distance from the centre of each of the elements of V, in 1D. ri then represents the distance from the centre in 2D and these are the values we want to interpolate to. I then only use half of r and V because they are symmetrical.
You might want to set all the NaNs to 0 afterwards because you can't interpolate the corners because their radius is larger than the radius of your furthest point in V.
Using your plotting code I get
and
The blue and magenta curves overlap exactly.
Explanation
Imagine that your vector, V, was only a 1-by-5 vector. Then this diagram shows what r and ri would be:
I didn't mark it on the diagram but r' would be the middle column. Now from the code we have
ri = bsxfun(#(x,y)(sqrt(x.^2+y.^2)),r,r');
and according to the diagram r = [2,1,0,1,2] so now for each pixel we have the euclidean distance from the centre so pixel (1,1) is going to be sqrt(r(1).^2+r(1).^2) which is sqrt(2.^2+2.^2) which is sqrt(8) as shown in the diagram.
Also you will notice that I have "greyed" out the corners pixels. These pixels are further from the centre than any point we have data for because the maximum radius (distance from the centre) of our data is 2 but sqrt(8) > sqrt(5) > 2 so you can't interpolate those data, you would have to extrapolate to get values for them. interp1 returns NaN for these points.
Why does the interpolation work? Think of the position of each pixel as referring to the centre of the pixel. Now in this diagram, the red circle is what happens when you rotate the outer elements (i.e. r==2) and the green is rotating the elements 1 further in (i.e. r==1). You'll see that the pixel that gets the distance of sqrt(2) (blue arrow) lies between these two radii when we rotate them and so we have to interpolate that distance between those two pixels.

Related

Find coordinates from a contour in Matlab

I suppose this is not something difficult but i wonder if there is any function or any optimal way.
Consider that after an image process i have a matrix-image with 0 everywhere and 1 at the contour.
Now i want to find the x y along that contour line
The important is that eg [ x(2) y(2) ] should be the next pixel to [x(1) y(1)]
I have used this:
[c h]=contour(image,1)
x=c(1,:)
y=c(2,:)
But the result is not very good and it gives some noise points which is very bad (and for some reason it appears mirrored)
If you have the image processing toolbox, I highly suggest using bwperim which returns a logical image where true is a perimeter or contour point and false otherwise.... not to mention that it's faster.
Try doing:
bw = bwperim(image == 1); % image == 1 to ensure binary
[y, x] = find(bw);
The first line of code finds an image that only contains contour points, and we can use find after that on the result to find the row and column locations. Here y represents the row and x represents the column locations.
If you desire that the contour is ordered, then use the bwtraceboundary function instead. However, this will require that you specify an initial contour point prior to running the function.
An easy way to do this would be to find any non-zero point along the contour of your object. You could use bwperim first and sample any point from here. Choosing just any point may not give you an actual contour point.
Therefore:
bw = bwperim(image == 1); % image == 1 to ensure binary
[y, x] = find(bw, 1); % Find the first contour point
ctr = bwtraceboundary(image == 1, [y, x], 'SE');
'SE' is the direction of where to look first given the initial contour point. Here I've chosen south east. This will produce a N x 2 matrix where the first column contains the rows and second column contains the columns of the ordered contour points starting at the initial position provided by y and x.
I have posted my complete solution to help other people:
Problem:
I have a grayscale image and i want to find the coordinates X Y in order along the contour .
Solution:
Set a threshold for black and white and make the image binary (optional)
`image=image>0.5 %This is optional but some may found it usefull`
Find the Start Point:
[yStart xStart]=find(image,1);
This will scan the image column by column from left to right and up to down and will return the first non zero pixel. So this will return the 'left-est up' pixel of the image. Remember, X is the column and Y is the row. Zero is at the top-left corner!
Find the contour:
contour=bwtraceboundary(image, [yStart, xStart],'NE');
or
contour = bwtraceboundary(image,[yStart xStart],'NE',8,Inf,'clockwise');
NE is the initial direction (NorthEast)
x=contour(:,2)
y=contour(:,1)
If the point [yStart xStart] is not on the contour of an image this will not work !
If you plot (x,y) that will be mirrored. This is because the zero at the coordinate system is at the top left corner of the image and not at the bottom left. To do it properly you can do this:
y=-y
y=y+abs(min(y))+1 % +1 is to avoid y=0

Finding points in array that is in the specified rectangle( matlab)

I have a matrix that is consists of some points of image.look at below
Cout=
[215,59;165,126;215,72;236,65;258,60;296,71;296,84;246,77;240,120;228,120;225,74;176,58;178,72];
Now I want to find points in rectangle below [x,y,width,height]
rec=[105,210,31,31]
How should I code it in Matlab?
Thanks.
Use inpolygon.[https://www.mathworks.com/help/matlab/ref/inpolygon.html]
HOW IT WORKS:
in = inpolygon(xq,yq,xv,yv) returns in indicating if the query points specified by xq and yq are inside or on the edge of the polygon area defined by xv and yv.
xq: x-coordinates of query points, specified as a scalar, vector, matrix, or multidimensional array(The size of xq must match the size of yq).
yq: y-coordinates of query points, specified as a scalar, vector, matrix, or multidimensional array.
xv: x-coordinates of polygon vertices, specified as a vector(The size of xv must match the size of yv).
yv: y-coordinates of polygon vertices, specified as a vector.
in: Indicator for the points inside or on the edge of the polygon area, returned as a logical array. in is the same size as xq and yq.
% points of image you're searching
% (x,y) are not the coordinates of matrices in MATLAB! And images are
% matrices. The coordinates of matrices are (row, column) which is NOT (x,y) - it's (y,x).
yq=Cout(:,1)
xq=Cout(:,2)
xv=[rec(1);rec(1);rec(1)+rec(3);rec(1)+rec(3);rec(1)];
yv=[rec(2);rec(2)+rec(4);rec(2)+rec(4);rec(2);rec(2)];
in = inpolygon(xq,yq,xv,yv)
I find 2 points by this way.
here is what you need (I think):
Cout= [235,65;296,71;296,84;240,120;229,119;224,74;165,126];
Rec=[105,210,31,31];
% set the range of the rectangle in x and y
xr=[Rec(2) (Rec(2)+Rec(4))];
yr=[Rec(1) (Rec(1)+Rec(3))];
% draw the rectangle for ref
rectangle('Position',Rec); hold on
% the next line is what you asked for, checking if points fall in the
% rectangle I chose here limits with < and >, but you may want <= and >= ...
id = Cout(:,1)<xr(end) & Cout(:,1)>xr(1) & Cout(:,2)<yr(end) & Cout(:,2)>yr(1);
% let's check:
plot(Cout(:,2),Cout(:,1),'x',Cout(id,2),Cout(id,1),'ro')

How to create a 3D matrix in MATLAB by rotating 2D matrix around its center column or center row?

I have a 2D MATLAB matrix, which is symmetric with respect to its center column. I want to rotate this matrix around its center column to produce a 3D matrix representing an object with a cylindrical symmetry.
The same thing I want to do with a different matrix, which is symmetric with respect to its center row. (This time I want to rotate it around its center row to produce the 3D matrix).
What I had in mind is to generalize to 3D the idea given in the link:
How to create a 2D image by rotating 1D vector of numbers around its center element?
But not knowing MATLAB well enough it is not a so straight forward task for me.
Can someone help please?
I just modified the accepted answer to 3D:
% generate symetric matrix
A = zeros(11,31);
A(4:8,10:22) = repmat([1:7 6:-1:1],[5 1]);
% symmetric x axis
n = floor(size(A,2)/2);
% A vector of distance (measured in pixels) from the center of vector V to each element of V
[r,y] = meshgrid([n:-1:0, 1:n],1:size(A,1));
% Now find the distance of each element of a square 2D matrix from it's centre. #(x,y)(sqrt(x.^2+y.^2)) is just the Euclidean distance function.
ri = sqrt( bsxfun( #(x,y)x.^2+y.^2,r,permute(r,[1 3 2]) ) );
yi = repmat(y,[1 1 size(A,2)]);
% Now use those distance matrices to interpole V
obj = interp2(r(:,1:n+1),y(:,1:n+1),A(:,1:n+1),ri,yi,'nearest');
obj(isnan(obj)) = 0;
% show
[xg,yg,zg] = meshgrid(1:size(obj,2),1:size(obj,1),1:size(obj,3));
scatter3(xg(:),yg(:),zg(:),10,obj(:)+1,'filled')
axis equal
UPDATE - if you don't want to use interp2 you can do:
obj = interp1(r(1,1:n+1).',A(:,1:n+1).',ri(1,:,:),'nearest');
obj = permute(obj,[4,3,2,1]);
obj(isnan(obj)) = 0;

Centroid calculation for a connected component in 3D volume using Matlab

I am trying to implement brain tumor segmentation on 3D brain MRI(.mha data type).
After preliminary segmentation, I am applying 26-neighbor connected component algorithm(using bwconncomp) to obtain the largest connected component by obtaining the component with the largest volume, following which I need to calculate the centroid of the resultant component.
I am not sure if my method of calculating the largest connected component and the centroid is correct, because the centroid obtained and its nearby voxels all have value 0.
Also I am having confusion with the representation of 3D voxel coordinates. For eg. if centroid=(x,y,z), does it correspond to x=row,y=column and z=2D slice?
Any help would be appreciated. Below is my code with the relevant part.
CC=bwconncomp(Ibin,26); %Input Black & White 3D data of size 240x240x155
Pixelid=regionprops(CC,'PixelIdxList');
[prow pcol]=size(Pixelid);
maxval=numel(Pixelid(1).PixelIdxList);
index=1;
for i=1:prow
number=numel([Pixelid(i).PixelIdxList]);
if (number>maxval) %calculating the component with max number of voxels
maxval=number;
index=i;
end
end
for i=1:prow
if i~=index
Ibin(Pixelid(i).PixelIdxList)=0;
end
end
CC1=bwconncomp(Ibin,26);
Cent=regionprops(CC1,'Centroid');
I changed your code to the following:
CC=bwconncomp(Ibin,26);
PixelIdxList = CC.PixelIdxList;
maxval = numel(PixelIdxList{1});
index = 1;
for ii = 1:length(PixelIdxList)
number = numel(PixelIdxList{ii});
if number > maxval
maxval = number;
index = ii;
end
end
[y,x,z] = ind2sub(size(Ibin),PixelIdxList{index})
centroid = [mean(x), mean(y), mean(z)];
bwconncomp already gives you a PixelIdxList so you don't have to use regionprops. The PixelIdxList lists pixels by their linear indices, so you have to convert them into subscripts to get x, y, and z coordinates. The first dimension in MATLAB matrix represents y coordinates, and second dimension represents x, while the third dimension represents z. Centroid is calculated by taking the mean x, y, and z coordinates of all the pixels contained in the object.

How do I draw a texture-mapped triangle in MATLAB?

I have a triangle in (u,v) coordinates in an image. I would like to draw this triangle at 3D coordinates (X,Y,Z) texture-mapped with the triangle in the image.
Here, u,v,X,Y,Z are all vectors with three elements representing the three corners of the triangle.
I have a very ugly, slow and unsatisfactory solution in which I:
extract a rectangular part of the image
transform it to 3D space with the transformation defined by the three points
draw it with surface
finally masking out everything that is not part of the triangle with AlphaData
Surely there must be an easier way of doing this?
I have what I think is a better solution for you involving two steps. First, it extracts a rectangular part of your image, half of which is the triangular section to be used as a texture map and half of which will be ignored. Then this texture map is applied to a 3-D surface object whose points are adjusted to render it as a triangle instead of a quadrilateral.
For the example I will show here, I will use the following values for your various parameters, assuming you have a triangle whose points are labeled as the "origin" (triangle vertex), point "A", and point "B" in the image space (as in the first image below):
x = [0.1 0.9 0.8]; % [xorigin xA xB] coordinates in 3-D space
y = [0.9 0.1 0.8]; % [yorigin yA yB] coordinates in 3-D space
z = [0.1 0.1 0.9]; % [zorigin zA zB] coordinates in 3-D space
origin = [150 350]; % Vertex of triangle in image space
U = [300 -50]; % Vector from origin to point A in image space
V = [50 -250]; % Vector from origin to point B in image space
img = imread('peppers.png'); % Sample image for texture map
Extracting the texture map via projective transformation:
This step uses the Image Processing Toolbox functions maketform and imtransform to perform a projective transformation of the part of the image containing the triangle you want to use as a texture map. Note that since images have to be rectangular, an additional triangular section defined by points (O,B,C) has to be included.
The triangular part of the image you want will be in the lower right half of the image, while the additional triangular "filler" part will be in the upper left. Note that this additional triangle can extend outside of the image, which will cause part of it to be filled with black by default. Here's the code to perform the projective transform illustrated above:
A = origin+U; % Point A
B = origin+V; % Point B
C = B-U; % Point C
[nRows, nCols, nPages] = size(img); % Image dimensions
inputCorners = [origin; ... % Corner coordinates of input space
A; ...
B; ...
C];
outputCorners = [1 nRows; ... % Corner coordinates of output space
nCols nRows; ...
nCols 1; ...
1 1];
tform = maketform('projective', ... % Make the transformation structure
inputCorners, ...
outputCorners);
triTexture = imtransform(img,tform, 'bicubic', ... % Transform the image
'xdata', [1 nCols], ...
'ydata', [1 nRows], ...
'size', [nRows nCols]);
Note that this code will create a final image triTexture that is the same size as the input image img.
Plotting the triangular texture-mapped surface:
Plotting the surface is now quite simple, assuming you've ordered the values in your x,y,z variables such that the coordinates for the origin point are in the first indices, the coordinates for point A are in the second indices, and the coordinates for point B are in the third indices. You can now create new sets of 2-by-2 surface coordinates X,Y,Z that contain two copies of point B, which causes only half of the surface to be rendered (i.e. the half containing the desired triangular image as a texture map). Here's the code to do this:
index = [3 3; 1 2]; % Index used to create 2-by-2 surface coordinates
X = x(index); % x coordinates of surface
Y = y(index); % y coordinates of surface
Z = z(index); % z coordinates of surface
hSurface = surf(X, Y, Z, triTexture, ... % Plot texture-mapped surface
'FaceColor', 'texturemap', ...
'EdgeColor', 'none');
axis equal % Use equal scaling on axes
axis([0 1 0 1 0 1]); % Set axes limits
xlabel('x-axis'); % x-axis label
ylabel('y-axis'); % y-axis label
zlabel('z-axis'); % z-axis label
And here's the resulting texture-mapped triangular surface it creates, with an inset added to show that the texture map contains the correct triangular part of the original image:
Would WARP help?
http://www.mathworks.com/access/helpdesk/help/toolbox/images/warp.html