I am working on rotating image manually in Matlab. Each time I run my code with a different image the previous images which are rotated are shown in the Figure. I couldn't figure it out. Any help would be appreciable.
The code is here:
[screenshot]
im1 = imread('gradient.jpg');
[h, w, p] = size(im1);
theta = pi/12;
hh = round( h*cos(theta) + w*abs(sin(theta))); %Round to nearest integer
ww = round( w*cos(theta) + h*abs(sin(theta))); %Round to nearest integer
R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
T = [w/2; h/2];
RT = [inv(R) T; 0 0 1];
for z = 1:p
for x = 1:ww
for y = 1:hh
% Using matrix multiplication
i = zeros(3,1);
i = RT*[x-ww/2; y-hh/2; 1];
%% Nearest Neighbour
i = round(i);
if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
im2(y,x,z) = im1(i(2),i(1),z);
end
end
end
end
x=1:ww;
y=1:hh;
[X, Y] = meshgrid(x,y); % Generate X and Y arrays for 3-D plots
orig_pos = [X(:)' ; Y(:)' ; ones(1,numel(X))]; % Number of elements in array or subscripted array expression
orig_pos_2 = [X(:)'-(ww/2) ; Y(:)'-(hh/2) ; ones(1,numel(X))];
new_pos = round(RT*orig_pos_2); % Round to nearest neighbour
% Check if new positions fall from map:
valid_pos = new_pos(1,:)>=1 & new_pos(1,:)<=w & new_pos(2,:)>=1 & new_pos(2,:)<=h;
orig_pos = orig_pos(:,valid_pos);
new_pos = new_pos(:,valid_pos);
siz = size(im1);
siz2 = size(im2);
% Expand the 2D indices to include the third dimension.
ind_orig_pos = sub2ind(siz2,orig_pos(2*ones(p,1),:),orig_pos(ones(p,1),:), (1:p)'*ones(1,length(orig_pos)));
ind_new_pos = sub2ind(siz, new_pos(2*ones(p,1),:), new_pos(ones(p,1),:), (1:p)'*ones(1,length(new_pos)));
im2(ind_orig_pos) = im1(ind_new_pos);
imshow(im2);
There is a problem with the initialization of im2, or rather, the lack of it. im2 is created in the section shown below:
if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
im2(y,x,z) = im1(i(2),i(1),z);
end
If im2 exists before this code is run and its width or height is larger than the image you are generating the new image will only overwrite the top left corner of your existing im2. Try initializing im2 by adding adding
im2 = zeros(hh, ww, p);
before
for z = 1:p
for x = 1:ww
for y = 1:hh
...
As a bonus it might make your code a little faster since Matlab won't have to resize im2 as it grows in the loop.
Related
This a program that I have, I already asked before for how to find the intersection on my image with a circle, and somebody has an answer it (thank you) and I have another problem...
a = imread('001_4.bmp');
I2 = imcrop(a,[90 5 93 180]);
[i,j]=size(I2);
x_hist=sum(I2,1);
y_hist=(sum(I2,2))';
x=1:j ; y=1:i;
centx=sum(x.*x_hist)/sum(x_hist);
centy=sum(y.*y_hist)/sum(y_hist);
BW = edge(I2,'Canny',0.5);
bw2 = imcomplement(BW);
circle = int32([centx,centy,40]);%<<----------
shapeInserter = vision.ShapeInserter('Fill',false);
release(shapeInserter);
set(shapeInserter,'Shape','Circles');
% construct binary image of circle only
bwCircle = step(shapeInserter,true(size(bw2)),circle);
% find the indexes of the intersection between the binary image and the circle
[i, j] = find ((bw2 | bwCircle) == 0);
figure
imshow(bw2 & bwCircle) % plot the combination of both images
hold on
plot(j, i, 'r*') % plot the intersection points
K = step(shapeInserter,bw2,circle);
[n,m]=size(i);
d=0;
k=1;
while (k < n)
d = d + sqrt((i(k+1)-i(k)).^2 + (j(k+1)-j(k)).^2);
k = k+1;
end
Q: How can I calculate all the existing intersection values(red *) in a clockwise direction?
Not sure, but I think that your teacher meant something different from the answer given in the previous question, because
CW direction can be a hint, not a additional problem
I've seen no clue that the circle should be drawn; for small radius circles are blocky and simple bw_circle & bw_edges may not work. For details please see "Steve on image processing" blog, "Intersecting curves that don't intersect"[1]
May be your teacher is rather old and wants Pascal-stile answer.
If my assumptions are correct the code below should be right
img = zeros(7,7); %just sample image, edges == 1
img(:,4) = 1; img(sub2ind(size(img),1:7,1:7)) = 1;
ccx = 4; % Please notice: x is for columns, y is for rows
ccy = 3;
rad = 2;
theta = [(pi/2):-0.01:(-3*pi/2)];
% while plotting it will appear CCW, for visual CW and de-facto CCW use
% 0:0.01:2*pi
cx = rad * cos(theta) + ccx; % gives slightly different data as for
cy = rad * sin(theta) + ccy; % (x-xc)^2 + (y-yc)^2 == rad^2 [2]
ccoord=[cy;cx]'; % Once again: x is for columns, y is for rows
[ccoord, rem_idx, ~] =unique(round(ccoord),'rows');
cx = ccoord(:,2);
cy = ccoord(:,1);
circ = zeros(size(img)); circ(sub2ind(size(img),cy,cx))=1;
cross_sum = 0;
figure, imshow(img | circ,'initialmagnification',5000)
hold on,
h = [];
for un_ang = 1:length(cx),
tmp_val= img(cy(un_ang),cx(un_ang));
if tmp_val == 1 %the point belongs to edge of interest
cross_sum = cross_sum + tmp_val;
h = plot(cx(un_ang),cy(un_ang),'ro');
pause,
set(h,'marker','x')
end
end
hold off
[1] https://blogs.mathworks.com/steve/2016/04/12/intersecting-curves-that-dont-intersect/
[2] http://matlab.wikia.com/wiki/FAQ#How_do_I_create_a_circle.3F
I want to find the corners of objects.
I tried the following code:
Vstats = regionprops(BW2,'Centroid','MajorAxisLength','MinorAxisLength',...
'Orientation');
u = [Vstats.Centroid];
VcX = u(1:2:end);
VcY = u(2:2:end);
[VcY id] = sort(VcY); % sorting regions by vertical position
VcX = VcX(id);
Vstats = Vstats(id); % permute according sort
Bv = Bv(id);
Vori = [Vstats.Orientation];
VRmaj = [Vstats.MajorAxisLength]/2;
VRmin = [Vstats.MinorAxisLength]/2;
% find corners of vertebrae
figure,imshow(BW2)
hold on
% C = corner(VER);
% plot(C(:,1), C(:,2), 'or');
C = cell(size(Bv));
Anterior = zeros(2*length(C),2);
Posterior = zeros(2*length(C),2);
for i = 1:length(C) % for each region
cx = VcX(i); % centroid coordinates
cy = VcY(i);
bx = Bv{i}(:,2); % edge points coordinates
by = Bv{i}(:,1);
ux = bx-cx; % move to the origin
uy = by-cy;
[t, r] = cart2pol(ux,uy); % translate in polar coodinates
t = t - deg2rad(Vori(i)); % unrotate
for k = 1:4 % find corners (look each quadrant)
fi = t( (t>=(k-3)*pi/2) & (t<=(k-2)*pi/2) );
ri = r( (t>=(k-3)*pi/2) & (t<=(k-2)*pi/2) );
[rp, ip] = max(ri); % find farthest point
tc(k) = fi(ip); % save coordinates
rc(k) = rp;
end
[xc,yc] = pol2cart(tc+1*deg2rad(Vori(i)) ,rc); % de-rotate, translate in cartesian
C{i}(:,1) = xc + cx; % return to previous place
C{i}(:,2) = yc + cy;
plot(C{i}([1,4],1),C{i}([1,4],2),'or',C{i}([2,3],1),C{i}([2,3],2),'og')
% save coordinates :
Anterior([2*i-1,2*i],:) = [C{i}([1,4],1), C{i}([1,4],2)];
Posterior([2*i-1,2*i],:) = [C{i}([2,3],1), C{i}([2,3],2)];
end
My input image is :
I got the following output image
The bottommost object in the image is not detected properly. How can I correct the code? It fails to work for a rotated image.
You can get all the points from the image, and use kmeans clustering and partition the points into 8 groups. Once partition is done, you have the points in and and you can pick what ever the points you want.
rgbImage = imread('your image') ;
%% crop out the unwanted white background from the image
grayImage = min(rgbImage, [], 3);
binaryImage = grayImage < 200;
binaryImage = bwareafilt(binaryImage, 1);
[rows, columns] = find(binaryImage);
row1 = min(rows);
row2 = max(rows);
col1 = min(columns);
col2 = max(columns);
% Crop
croppedImage = rgbImage(row1:row2, col1:col2, :);
I = rgb2gray(croppedImage) ;
%% Get the white regions
[y,x,val] = find(I) ;
%5 use kmeans clustering
[idx,C] = kmeans([x,y],8) ;
%%
figure
imshow(I) ;
hold on
for i = 1:8
xi = x(idx==i) ; yi = y(idx==i) ;
id1=convhull(xi,yi) ;
coor = [xi(id1) yi(id1)] ;
[id,c] = kmeans(coor,4) ;
plot(coor(:,1),coor(:,2),'r','linewidth',3) ;
plot(c(:,1),c(:,2),'*b')
end
Now we are able to capture the regions..the boundary/convex hull points are in hand. You can do what ever math you want with the points.
Did you solve the problem? I Looked into it and it seems that the rotation given by 'regionprops' seems to be off. To fix that I've prepared a quick solution: I've dilated the image to close the gaps, found 4 most distant peaks of each spine, and then validated if a peak is on the left, or on the right of the centerline (that I have obtained by extrapolating form sorted centroids). This method seems to work for this particular problem.
BW2 = rgb2gray(Image);
BW2 = imbinarize(BW2);
%dilate and erode will help to remove extra features of the vertebra
se = strel('disk',4,4);
BW2_dilate = imdilate(BW2,se);
BW2_erode = imerode(BW2_dilate,se);
sb = bwboundaries(BW2_erode);
figure
imshow(BW2)
hold on
centerLine = [];
corners = [];
for bone = 1:length(sb)
x0 = sb{bone}(:,2) - mean(sb{bone}(:,2));
y0 = sb{bone}(:,1) - mean(sb{bone}(:,1));
%save the position of the centroid
centerLine = [centerLine; [mean(sb{bone}(:,1)) mean(sb{bone}(:,2))]];
[th0,rho0] = cart2pol(x0,y0);
%make sure that the indexing starts at the dip, not at the corner
lowest_val = find(rho0==min(rho0));
rho1 = [rho0(lowest_val:end); rho0(1:lowest_val-1)];
th00 = [th0(lowest_val:end); th0(1:lowest_val-1)];
y1 = [y0(lowest_val:end); y0(1:lowest_val-1)];
x1 = [x0(lowest_val:end); x0(1:lowest_val-1)];
%detect corners, using smooth data to remove noise
[pks,locs] = findpeaks(smooth(rho1));
[pksS,idS] = sort(pks,'descend');
%4 most pronounced peaks are where the corners are
edgesFndCx = x1(locs(idS(1:4)));
edgesFndCy = y1(locs(idS(1:4)));
edgesFndCx = edgesFndCx + mean(sb{bone}(:,2));
edgesFndCy = edgesFndCy + mean(sb{bone}(:,1));
corners{bone} = [edgesFndCy edgesFndCx];
end
[~,idCL] = sort(centerLine(:,1),'descend');
centerLine = centerLine(idCL,:);
%extrapolate the spine centerline
yDatExt= 1:size(BW2_erode,1);
extrpLine = interp1(centerLine(:,1),centerLine(:,2),yDatExt,'spline','extrap');
plot(centerLine(:,2),centerLine(:,1),'r')
plot(extrpLine,yDatExt,'r')
%find edges to the left, and to the right of the centerline
for bone = 1:length(corners)
x0 = corners{bone}(:,2);
y0 = corners{bone}(:,1);
for crn = 1:4
xCompare = extrpLine(y0(crn));
if x0(crn) < xCompare
plot(x0(crn),y0(crn),'go','LineWidth',2)
else
plot(x0(crn),y0(crn),'ro','LineWidth',2)
end
end
end
Solution
lesion image
I have an irregularly shaped object in which I have to find the greatest and smallest diameter.
To find the greatest diameter, I extracted the boundary points and found the distances between all the points. I took the maximum distance amongst those distances which gave me my greatest diameter.
boundaries = bwboundaries(binaryImage);
numberOfBoundaries = size(boundaries, 1);
for blobIndex = 1 : numberOfBoundaries
thisBoundary = boundaries{blobIndex};
x = thisBoundary(:, 2); % x = columns.
y = thisBoundary(:, 1); % y = rows.
% Find which two boundary points are farthest from each other.
maxDistance = -inf;
for k = 1 : length(x)
distances = sqrt( (x(k) - x) .^ 2 + (y(k) - y) .^ 2 );
[thisMaxDistance, indexOfMaxDistance] = max(distances);
if thisMaxDistance > maxDistance
maxDistance = thisMaxDistance;
index1 = k;
index2 = indexOfMaxDistance;
end
end
I have attached my image containing the longest diameter.
I also need a line segment that passes through the centroid connecting the two boundary points whose length is shortest. When I try to find the shortest diameter by modifying the above code, to find min(distances), I am getting an error that says:
Error using griddedInterpolant
The coordinates of the input points must be finite values; Inf and NaN are not permitted.
What do I need to do to find the shortest "diameter" (that is, passing through the centroid) of this object?
it's possible to use a polar image like this:
lesion = imread('lesion.jpg');
bw = lesion > 100;
c = regionprops(bw,'Centroid');
c = c.Centroid;
% polar args
t = linspace(0,2*pi,361);
t(end) = [];
r = 0:ceil(sqrt(numel(bw)/4));
[tg,rg] = meshgrid(t,r);
[xg,yg] = pol2cart(tg,rg);
xoff = xg + c(1);
yoff = yg + c(2);
% polar image
pbw = interp2(double(bw),xoff,yoff,'nearest') == 1;
[~,radlen] = min(pbw,[],1);
radlen(radlen == 1) = max(r);
n = numel(radlen);
% add two edges of line to form diameter
diamlen = radlen(1:n/2) + radlen(n/2+1:n);
% find min diameter
[mindiam,tminidx1] = min(diamlen);
tmin = t(tminidx1);
rmin = radlen(tminidx1);
tminidx2 = tminidx1 + n/2;
xx = [xoff(radlen(tminidx1),tminidx1) xoff(radlen(tminidx2),tminidx2)];
yy = [yoff(radlen(tminidx1),tminidx1) yoff(radlen(tminidx2),tminidx2)];
% viz
figure;
subplot(121);
imshow(pbw);
title('polar image');
subplot(122);
imshow(bw);
hold on
plot(c(1),c(2),'or')
plot(xx,yy,'g')
legend('centroid','shortest diameter');
and the output is:
I read a DICOM image and for a variety of reasons, I had to turn the image matrix in a row vector.
After performing various operations on the bits of the vector, I need to reprocess the vector in a DICOM image of the same size as the original.
I've done all these steps but when I go to display the resulting image, this is rotated.
This is what I get:
That's part of the code:
function [I0, Iw] = watIns(filename, w)
I0 = dicomread(filename);
figure(1);
imshow(I0, []);
title('(1) I0 originale');
info = dicominfo(filename);
width = info.Width;
height = info.Height;
size = info.FileSize;
k = info.BitDepth;
% I extract the first k pixels and memorize their LBS in a variable S.
x = 1 : k;
y = 1;
firstKPixel = I0(x, y);
% convert in binary
firstKPixel2 = 0*firstKPixel;
for i = 1 : length(firstKPixel)
if firstKPixel(i) == 0
firstKPixel2(i) = 0;
else
firstKPixel2(i) = dec2bin(firstKPixel(i), 'left-msb');
end
end
% I take the LSB of each element in firstKPixel2 and concatenate in the string S
S = '';
for i = 1 : k
c = firstKPixel2(i, :);
s = num2str(c(end));
S = strcat(S, s);
end
% I compute the vector corresponding to I0 but without the first 0 pixels and the corresponding histogram
[vecComp, histComp] = histKtoEnd(I0, 0, k);
% I compute the vector corresponding to I0 but without the first k pixels and the corresponding histogram
[vecWithoutKPixel, histWithoutKPixel] = histKtoEnd(I0, k, k);
L = ...; % is a vector of values
% I save l_0 in the LSB of the first k pixels.
% prendo l_0, ovvero il primo elemento di L
l_0 = L(1);
l_02 = fliplr(bitget(l_0, 1:k));
% I take the LSB of each element in firstKPixel2 and I sret it to the i-th element of l0_2
for i = 1 : k
c = firstKPixel2(i, :);
c(end) = l_02(i);
firstKPixel2(i, :) = c;
end
% convert to decimal each element of firstKPixel2
for i = 1 : length(firstKPixel2)
str = int2str(firstKPixel2(i));
firstKPixel2_lsb10(i) = bin2dec(str);
end
% I set first k pixels in the image to those just modified
vecComp(1 : k) = firstKPixel2_lsb10(1 : k);
% Transform the vector image
mat = reshape(vecComp, [width, height]);
dicomwrite(mat, './I1.dcm', 'CompressionMode', 'None');
I1 = dicomread('./I1.dcm');
figure(7);
imshow(I1, []); % ROTATE IMAGE!!!
% ...
end
histKtoEnd function is:
function [vecWithoutKPixel, hist] = histKtoEnd(image, k, colorDepth)
imageVec = reshape(image.', [], 1);
l = length(imageVec);
vecWithoutKPixel = imageVec((k+1) : l-1);
vecWithoutKPixel(end+1) = imageVec(l);
hist = zeros(1, 2^colorDepth);
for i = 0 : (2^colorDepth - 1)
grayI = (vecWithoutKPixel == i);
hist(1, i+1) = sum(grayI(:));
end
end
I read here that Matlab shows images like a matrix with the first coordinates (rows) going top-down and the second (columns) left-right.
I couldn't solve, can anyone help me?
Thank you!
Somehow in the unrolling, processing and rolling of your data it seems to get transposed. You can try to find why that happens, but if you do not care, you can always just transpose the result in the end by
mat = reshape(vecComp, [width, height]).';
I setup and meshed a domain using Matlab's PDE toolbox. Along the boundary, is there someway to get the length of each element of the mesh? And the flux in the normal direction? (the bc are Dirichlet)
Edit:
See example code
RMax = 20;
RL = 1;
RU = 0.5;
HN = 5;
HL = 2;
HTT = 3;
HU = 1.5;
VL = -150;
p = [RL,0;RL,HN;0,HN+HL;0,HN+HL+HTT;RU,HN+HL+HTT+HU;RMax,HN+HL+HTT+HU;RMax,0];
t = [1;1;0;1;1;0;0];
v = [VL;VL;0;0;0;0;0];
dx = 0.5;
dy = 0.5;
bc = cell(size(t));
for i = 1:length(t)
if t(i) == 0
bc{i} = {'u', v(i)};
elseif t(i) == 1
bc{i} = {'g', v(i), 'q', 1};
else
error('Unrecognized boundary condition type.')
end
end
model = createpde;
gd = [2; size(p,1); p(:,1) ; p(:,2)];
ns = char('domain')';
sf = 'domain';
g = decsg(gd,sf,ns);
geometryFromEdges(model,g);
generateMesh(model, 'Hmax', min([dx,dy])/3, 'MesherVersion','R2013a');
for i = 1:size(bc,1)
applyBoundaryCondition(model, 'Edge', i, bc{i}{:});
end
u = assempde( model , 'x' , 0 , 0 );
pdemesh(model)
Edit: 2015-12-17 18:54 GMT
There are 2 points in the e shown at 1 and 2 in the figure below. I want to know the coordinate of 3 so I know which direction is into the domain.
You can answer your first question by using meshToPet to convert to [P,E,T] form:
[p,e,t] = meshToPet(model.Mesh);
x1 = p(1,e(1,:)); % x-coordinates of first point in each mesh edge
x2 = p(1,e(2,:)); % x-coordinates of second point in each mesh edge
y1 = p(2,e(1,:)); % y-coordinates of first point in each mesh edge
y2 = p(2,e(2,:)); % y-coordinates of second point in each mesh edge
% Plot first points of mesh edge
plot(x1,y1,'b.-',x1(1),y1(1),'go',x1(end),y1(end),'ro');
% Euclidean distance between first and second point in each edge
d = sqrt((x1-x2).^2+(y1-y2).^2);
I'm assuming you just want the lengths of the mesh edge/boundary. You can use similar methods to get the lengths of every single triangle using the t matrix.
As far as flux goes, there's pdecgrad. I think the following may work:
...
c = 'x';
u = assempde(model, c, 0, 0);
[p,e,t] = meshToPet(model.Mesh);
[cgxu,cgyu] = pdecgrad(p,t,c,u);