I want to use the Hough transform to detect lines in my image.But instead of plotting the lines I want to delete each line detected in my original image.
image=imread('image.jpg');
image = im2bw(image);
BW=edge(image,'canny');
imshow(BW);
figure,imshow(BW);
[H,T,R] = hough(BW);
P = houghpeaks(H,100,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
Now after this I have got all the lines. But I want to delete all these lines from my original image, keeping rest of the image as before. Is there some way I can do this?
Edit I am uploading an image.I want to delete all the lines and keep the circular part.This is just an example image.Basically my objective is to delete the line segments and keep rest of the image
The issue you have is that your lines are thicker than one pixel.
The lines from the hough transform seem to be one pixel thick and
that doesn't help.
I propose that you delete the lines that you get from the Hough transform first.
This will sort of divide the hockey rink of whatever it is into segments
that will be easier to process.
Then you label each segment with bwlabel. For each object, find the
endpoints and fit a line between the endpoints. If the line and the object
have more pixels in common than a certain threshold, then we say that the object
is a line and we delete it from the image.
You may have to play around with the Hough transform's threshold value.
This technique has some flaws though. It will delete a filled square,
rectangle or circle but you haven't got any of those so you should be ok.
Results
Explanation
This is your code that I modified a bit. I removed the gradient because it
it easier to work with solid objects. The gradient gave very thin lines.
I also work on the complement image because the bw functions work with 1
as forgound rather than 0 as in your original image.
org_image_bw=im2bw(double(imread('http://i.stack.imgur.com/hcphc.png')));
image = imcomplement(org_image_bw);
[H,T,R] = hough(image);
P = houghpeaks(H,100,'threshold',ceil(0.27*max(H(:))));
lines = houghlines(image,T,R,P,'FillGap',5,'MinLength',7);
Loop through the lines you have got and delete them
processed_image = image;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
% // Use the question of a line y = kx + m to calulate x,y
% // Calculate the maximum number of elements in a line
numOfElems = max(max(xy(:,1))-min(xy(:,1)),max(xy(:,2))-min(xy(:,2)) ) ;
% // Cater for the special case where the equation of a line is
% // undefined, i.e. there is only one x value.
% // We use linspace rather than the colon operator because we want
% // x and y to have the same length and be evenly spaced.
if (diff(xy(:,1)) == 0)
y = round(linspace(min(xy(:,2)),max(xy(:,2)),numOfElems));
x = round(linspace(min(xy(:,1)),max(xy(:,1)),numOfElems));
else
k = diff(xy(:,2)) ./ diff(xy(:,1)); % // the slope
m = xy(1,2) - k.*xy(1,1); % // The crossing of the y-axis
x = round(linspace(min(xy(:,1)), max(xy(:,1)), numOfElems));
y = round(k.*x + m); % // the equation of a line
end
processed_image(y,x) = 0; % // delete the line
end
This is what the image looks after we have deleted the detected lines. Please note that the original hockey rink and been divided into multiple objects.
Label the remaining objects
L = bwlabel(processed_image);
Run through each object and find the end points.
Then fit a line to it. If, let's say 80% the fitted line covers
the object, then it is a line.
A fitted line could look like this. The diagonal blue line represents the fitted line and covers most of
the object (the white area). We therefore say that the object is a line.
% // Set the threshold
th = 0.8;
% // Loop through the objects
for objNr=1:max(L(:))
[objy, objx] = find(L==objNr);
% Find the end points
endpoints = [min(objx) min(objy) ...
;max(objx) max(objy)];
% Fit a line to it. y = kx + m
numOfElems = max(max(endpoints(:,1))-min(endpoints(:,1)),max(endpoints(:,2))-min(endpoints(:,2)) ) ;
% // Cater for the special case where the equation of a line is
% // undefined, i.e. there is only one x value
if (diff(endpoints(:,1)) == 0)
y = round(linspace(min(endpoints(:,2)),max(endpoints(:,2)),numOfElems));
x = round(linspace(min(endpoints(:,1)),max(endpoints(:,1)),numOfElems));
else
k = diff(endpoints(:,2)) ./ diff(endpoints(:,1)); % the slope
m = endpoints(1,2) - k.*endpoints(1,1); % The crossing of the y-axis
x = round(linspace(min(endpoints(:,1)), max(endpoints(:,1)), numOfElems));
y = round(k.*x + m);
% // Set any out of boundary items to the boundary
y(y>size(L,1)) = size(L,1);
end
% // Convert x and y to an index for easy comparison with the image
% // We sort them so that we are comparing the same pixels
fittedInd = sort(sub2ind(size(L),y,x)).';
objInd = sort(sub2ind(size(L),objy,objx));
% // Calculate the similarity. Intersect returns unique entities so we
% // use unique on fittedInd
fitrate = numel(intersect(fittedInd,objInd)) ./ numel(unique(fittedInd));
if (fitrate >= th)
L(objInd) = 0;
processed_image(objInd) = 0;
% // figure(1),imshow(processed_image)
end
end
Display the result
figure,imshow(image);title('Original');
figure,imshow(processed_image);title('Processed image');
Complete example
org_image_bw=im2bw(double(imread('http://i.stack.imgur.com/hcphc.png')));
image = imcomplement(org_image_bw);
[H,T,R] = hough(image);
P = houghpeaks(H,100,'threshold',ceil(0.27*max(H(:))));
lines = houghlines(image,T,R,P,'FillGap',5,'MinLength',7);
processed_image = image;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
% // Use the question of a line y = kx + m to calulate x,y
%Calculate the maximum number of elements in a line
numOfElems = max(max(xy(:,1))-min(xy(:,1)),max(xy(:,2))-min(xy(:,2)) ) ;
% // Cater for the special case where the equation of a line is
% // undefined, i.e. there is only one x value.
% // We use linspace rather than the colon operator because we want
% // x and y to have the same length and be evenly spaced.
if (diff(xy(:,1)) == 0)
y = round(linspace(min(xy(:,2)),max(xy(:,2)),numOfElems));
x = round(linspace(min(xy(:,1)),max(xy(:,1)),numOfElems));
else
k = diff(xy(:,2)) ./ diff(xy(:,1)); % the slope
m = xy(1,2) - k.*xy(1,1); % The crossing of the y-axis
x = round(linspace(min(xy(:,1)), max(xy(:,1)), numOfElems));
y = round(k.*x + m); % // the equation of a line
end
processed_image(y,x) = 0; % // delete the line
end
% // Label the remaining objects
L = bwlabel(processed_image);
% // Run through each object and find the end points.
% // Then fit a line to it. If, let's say 80% the fitted line covers
% // the object, then it is a line.
% // Set the threshold
th = 0.8;
% // Loop through the objects
for objNr=1:max(L(:))
[objy, objx] = find(L==objNr);
% Find the end points
endpoints = [min(objx) min(objy) ...
;max(objx) max(objy)];
% Fit a line to it. y = kx + m
numOfElems = max(max(endpoints(:,1))-min(endpoints(:,1)),max(endpoints(:,2))-min(endpoints(:,2)) ) ;
% Cater for the special case where the equation of a line is
% undefined, i.e. there is only one x value
if (diff(endpoints(:,1)) == 0)
y = round(linspace(min(endpoints(:,2)),max(endpoints(:,2)),numOfElems));
x = round(linspace(min(endpoints(:,1)),max(endpoints(:,1)),numOfElems));
else
k = diff(endpoints(:,2)) ./ diff(endpoints(:,1)); % the slope
m = endpoints(1,2) - k.*endpoints(1,1); % The crossing of the y-axis
x = round(linspace(min(endpoints(:,1)), max(endpoints(:,1)), numOfElems));
y = round(k.*x + m);
% // Set any out of boundary items to the boundary
y(y>size(L,1)) = size(L,1);
end
% // Convert x and y to an index for easy comparison with the image
% // We sort them so that we are comparing the same pixels
fittedInd = sort(sub2ind(size(L),y,x)).';
objInd = sort(sub2ind(size(L),objy,objx));
% Calculate the similarity. Intersect returns unique entities so we
% use unique on fittedInd
fitrate = numel(intersect(fittedInd,objInd)) ./ numel(unique(fittedInd));
if (fitrate >= th)
L(objInd) = 0;
processed_image(objInd) = 0;
% // figure(1),imshow(processed_image)
end
end
% // Display the result
figure,imshow(image);title('Original');
figure,imshow(processed_image);title('Processed image');
You could use J. E. Bresenham's algorightm. It is implemented by A. Wetzler in the following matlab function, which I tested myself.
The algorithm will give you the pixel coordinates of where the line would be, given that you will provide the start and end point of the line, which is already given in lines in your code above.
Here is the code I used, which uses the matlab function referenced above:
%This is your code above ========
image=imread('hcphc.png');
image = im2bw(image);
BW=edge(image,'canny');
imshow(BW);
figure,imshow(BW);
[H,T,R] = hough(BW);
P = houghpeaks(H,100,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
% =========
% Proposed solution:
% This will work for as many lines as you detected
for k=1:length(lines)
% Call Bresenham's algorithm
[x, y] = bresenham(lines(k).point1(1), lines(k).point1(2), ...
lines(k).point2(1), lines(k).point2(2));
% This is where you replace the line, here I use 0, but you can use
% whatever you want. However, note that if you use BW, you should only
% replace with 0 or 1, because is a logical image. If you want to use
% the original image, well, you know what to do.
BW(y, x) = 0;
% And now watch the lines disapear! (you can remove this line)
imagesc(BW), drawnow; pause(1);
end
Remember, download the matlab function first.
Related
I'm trying to fill an area between two curves with respect to a function which depends on the values of the curves.
Here is the code of what I've managed to do so far
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
N=[n_vec,fliplr(n_vec)];
X=[x_vec,fliplr(y_vec)];
figure(1)
subplot(2,1,1)
hold on
plot(n_vec,x_vec,n_vec,y_vec)
hp = patch(N,X,'b')
plot([n_vec(i) n_vec(i)],[x_vec(i),y_vec(i)],'linewidth',5)
xlabel('n'); ylabel('x')
subplot(2,1,2)
xx = linspace(y_vec(i),x_vec(i),100);
plot(xx,cc(xx,y_vec(i),x_vec(i)))
xlabel('x'); ylabel('c(x)')
This code produces the following graph
The color code which I've added represent the color coding that each line (along the y axis at a point on the x axis) from the area between the two curves should be.
Overall, the entire area should be filled with a gradient color which depends on the values of the curves.
I've assisted the following previous questions but could not resolve a solution
MATLAB fill area between lines
Patch circle by a color gradient
Filling between two curves, according to a colormap given by a function MATLAB
NOTE: there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
The surf plot method
The same as the scatter plot method, i.e. generate a point grid.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
Generate a logical array indicating whether the points are inside the polygon, but no need to extract the points:
in = inpolygon(px, py, N, X);
Generate Z. The value of Z indicates the color to use for the surface plot. Hence, it is generated using the your function cc.
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
Set Z values for points outside the area of interest to NaN so MATLAB won't plot them.
pz(~in) = nan;
Generate a bounded colourmap (delete if you want to use full colour range)
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
Finally, plot.
figure;
colormap(jet)
surf(px,py,pz,'edgecolor','none');
view(2) % x-y view
Feel free to turn the image arround to see how it looks like in the Z-dimention - beautiful :)
Full code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
% generate z
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
pz(~in) = nan;
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
% plot
figure;
colormap(c)
surf(px,py,pz,'edgecolor','none');
view(2)
You can use imagesc and meshgrids. See comments in the code to understand what's going on.
Downsample your data
% your initial upper and lower boundaries
n_vec_long = linspace(2,10,1000000);
f_ub_vec_long = linspace(2, 10, length(n_vec_long));
f_lb_vec_long = abs(sin(n_vec_long));
% downsample
n_vec = linspace(n_vec_long(1), n_vec_long(end), 1000); % for example, only 1000 points
% get upper and lower boundary values for n_vec
f_ub_vec = interp1(n_vec_long, f_ub_vec_long, n_vec);
f_lb_vec = interp1(n_vec_long, f_lb_vec_long, n_vec);
% x_vec for the color function
x_vec = 0:0.01:10;
Plot the data
% create a 2D matrix with N and X position
[N, X] = meshgrid(n_vec, x_vec);
% evaluate the upper and lower boundary functions at n_vec
% can be any function at n you want (not tested for crossing boundaries though...)
f_ub_vec = linspace(2, 10, length(n_vec));
f_lb_vec = abs(sin(n_vec));
% make these row vectors into matrices, to create a boolean mask
F_UB = repmat(f_ub_vec, [size(N, 1) 1]);
F_LB = repmat(f_lb_vec, [size(N, 1) 1]);
% create a mask based on the upper and lower boundary functions
mask = true(size(N));
mask(X > F_UB | X < F_LB) = false;
% create data matrix
Z = NaN(size(N));
% create function that evaluates the color profile for each defined value
% in the vectors with the lower and upper bounds
zc = #(X, ub, lb) 1 ./ (1 + (exp(-X) ./ (exp(-ub) - exp(-lb))));
CData = zc(X, f_lb_vec, f_ub_vec); % create the c(x) at all X
% put the CData in Z, but only between the lower and upper bound.
Z(mask) = CData(mask);
% normalize Z along 1st dim
Z = normalize(Z, 1, 'range'); % get all values between 0 and 1 for colorbar
% draw a figure!
figure(1); clf;
ax = axes; % create some axes
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
xlabel('n')
ylabel('x')
This already looks kinda like what you want, but let's get rid of the blue area outside the boundaries. This can be done by creating an 'alpha mask', i.e. set the alpha value for all pixels outside the previously defined mask to 0:
figure(2); clf;
ax = axes; % create some axes
hold on;
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
% set a colormap
colormap(flip(hsv(100)))
% set alpha for points outside mask
Calpha = ones(size(N));
Calpha(~mask) = 0;
sc.AlphaData = Calpha;
% plot the other lines
plot(n_vec, f_ub_vec, 'k', n_vec, f_lb_vec, 'k' ,'linewidth', 1)
% set axis limits
xlim([min(n_vec), max(n_vec)])
ylim([min(x_vec), max(x_vec)])
there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
It is difficult to achieve this using patch.
However, you may use scatter plots to "fill" the area with coloured dots. Alternatively, and probably better, use surf plot and generate z coordinates using your cc function (See my seperate solution).
The scatter plot method
First, make a grid of points (resolution 500*500) inside the rectangular space bounding the two curves.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
figure;
scatter(px(:), py(:), 1, 'r');
The not-interesting figure of the point grid:
Next, extract the points inside the polygon defined by the two curves.
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
hold on;
scatter(px, py, 1, 'k');
Black points are inside the area:
Finally, create color and plot the nice looking gradient colour figure.
% create color for the points
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s'); % use size 16, filled square markers.
Note that you may need a fairly dense grid of points to make sure the white background won't show up. You may also change the point size to a bigger value (won't impact performance).
Of cause, you may use patch to replace scatter but you will need to work out the vertices and face ids, then you may patch each faces separately with patch('Faces',F,'Vertices',V). Using patch this way may impact performance.
Complete code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate point grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
% generate color
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s');
I am currently working on a project for my Chemical Engineering class called Buffon's needle. The purpose of this project is to use MATLAB to get an estimate for pi and then to make a "cartoon" which will show the needles on a 10x10 graph with lines every 1 unit apart, with needles crossing the line being one color, and needles not crossing being another. I have found the pi estimate and i have created the graph, but my lines are not the one unit in length like they should be, instead the needles are all different lengths. if anyone could help me with this problem it would be much appreciated. my two scripts are below
clear all;
close all;
clc;
format compact
% Script to illustrate the estimation of pi value by using Buffon's needle
% experiment
% set number of separate experiments
nExperiments = 1000;
% set number of separate trials
nTrials = 3;
% total number of dropped needles is directly based on number of trials and
% number of experiments
ndropped=nTrials.*nExperiments;
% spacing between the parallel lines
spacing = 1;
% length of the needle
L = spacing;
% the lower bound of x coordinate.
a = 10;
totalhits = 0;
for i = 1:nTrials
% keeps track of the number of hits
hits = 0;
% keeps track of the number of times the needle doesn't hit the
% any of the lines
nothits = 0;
for j = 1:nExperiments
[outcome,endpoints,angle] = needle_drop(spacing,L);
if outcome
hits = hits + 1;
endpointsHitList(:,:,hits) = endpoints;
else
nothits = nothits + 1;
endpointsNotHitList(:,:,nothits) = endpoints;
end
angleList(j) = angle;
end
scatter(1:nExperiments,angleList);
xlabel('Experiments');
ylabel('Angles');
piestimate(i) = (2*L/spacing)/(hits/nExperiments);
end
fprintf('The average value of pi is %f plus or minus %f after %d trials of %d experiments with %d total number of dropped needle.\n',mean(piestimate),std(piestimate),nTrials,nExperiments,ndropped);
figure
hold on
% plot the vertical separations
for i = 0:spacing:a
p1 = plot([i,i],[0 11],'k','LineWidth',2);
end
% plot the needles that hit the vertical separation
for i = 1:hits
p2 = plot(endpointsHitList(:,1,i),endpointsHitList(1,:,i),['-','b']);
end
% plot the needles that don't hit the vertical separation
for i = 1:nothits
p3 = plot(endpointsNotHitList(:,1,i),endpointsNotHitList(1,:,i),['-','r']);
end
axis([-2,12 -2 12]);
legend([p1 p2 p3],'Vertical Separations','Hits','Not Hits')
title('Buffon Needle Experiment');
xlabel('x-axis');
ylabel('y-axis');
figure
histogram(piestimate)
title('Histogram of pi estimate');
This below is my function needle_drop:
function [outcome,endpoints,theta] = needle_drop(spacing,L)
% spacing = spacing between the parallel lines spacing
% L = length of the needle
% spacing = 1;
% % In the special case where the length of the needle is equal to the grid spacing
% % between the parallel lines
% L = spacing;
% a is the lower bound of x coordinate. b is the upper bound.
% the needle position will be randomly between 0 and 10.
a = 0;
b = 10;
% generate random number r1 in [0,1]
r1 = rand;
% sample a value of the angle uniformly distributed over the interval
% from zero to ninety degrees
theta = (pi/2)*r1;
% the projection of half the length of the needle horizontally: S
S = (L/2)*cos(theta);
% Another random number r2 is generated
% this corresponds to x,y coordinate
r2 = a + (b-a).*rand(1,2);
% we need to take care of the offset.
% if the x coordinate is between 0 and d then offset is 0 if xcord is
% between d and 2d then offset is d and likewise for other values.
offset = floor(r2(1));
% The sampled position T of the center of the needle is next compared to the
% sampled projection of half the length of the needle
if r2(1)-S <=0+offset || r2(1)+S >=spacing+offset
outcome = 1;
else
outcome = 0;
end
% the projection of half the length of the needle vertically: V
V = L/2*sin(theta);
endpoints = [r2(1)-S,r2(2)+V;r2(1)+S,r2(2)-V];
You made an indexing mistake. Your function returns endpoints:
endpoints = [ r2(1)-S, r2(2)+V; ...
r2(1)+S, r2(2)-V ];
Simplified,
endpoints = [ start_x, start_y; ...
end_x, end_y ];
These are collected in a 3D matrix, which you then plot:
p2 = plot( endpointsHitList(:,1,i), endpointsHitList(1,:,i), ['-','b'] );
% ^ x-coordinates ^ y-coordinates
Thus, here you are plotting a line with x-coordinates [start_x,end_x], and y-coordinates [start_x,start_y]! This latter should have been [start_y,end_y].
This should have been:
p2 = plot( endpointsHitList(:,1,i), endpointsHitList(:,2,i), ['-','b'] );
% ^^^ get second column
The same mistake happens when plotting endpointsNotHitList.
I'm trying to compute the sum of the level (z axis) values inside a contour:
I've managed to obtain the lines (or edges) of the contour, so I have the limits of each line:
What I want is to sum all the levels in the z axis of the contour that are inside the outer blue line in the second plot, to compare it with the sum of the values of outside the blue line. Is there any way to do this? The code I have so far is:
C = contourc(f, t, abs(tfr));
%extracts info from contour
sz = size(C,2); % Size of the contour matrix c
ii = 1; % Index to keep track of current location
jj = 1; % Counter to keep track of # of contour lines
while ii < sz % While we haven't exhausted the array
n = C(2,ii); % How many points in this contour?
s(jj).v = C(1,ii); % Value of the contour
s(jj).x = C(1,ii+1:ii+n); % X coordinates
s(jj).y = C(2,ii+1:ii+n); % Y coordinates
ii = ii + n + 1; % Skip ahead to next contour line
jj = jj + 1; % Increment number of contours
end
So after you run the code in the question you have the coordinates of each contour in the array S. Assuming you have variables f and t of the form f = 94:0.1:101 and t = 0:1000 or similar, and the that value you want to sum are abs(tfr) you should be able to use
[fg, tg] = meshgrid(f,t)
is_inside = inpolygon(fg,tg, S(1).x, S(1).y)
integral = sum(abs(tfr(is_inside))
And similarly for other entries in S. See help for inpolygon for more examples. You can use ~is_inside for the points outside the curve
I'm very new to Matlab. I'm learning some image manipulation basics, and I'm a bit confused on how to write a translation without using imtranslate.
this is my code but it just displays a black background. Thank you.
img = imread('name2.png');
figure(1);
% pixel matrix
[orig_x, orig_y,z] = size(img);
final_x = 600;
final_y = 600;
% define the final array with calculated dimensions and fill the array with zeros ie.,black
final_img = uint8(zeros([final_x final_y 3 ]));
for i = 1 : size(final_img, 1)
for j = 1 : size(final_img, 2)
new_x = img(i) + 5;
new_y = img(j) + 5;
% fprintf('X: %f\n',new_x); % prints 255
final_img(i) = new_x;
final_img(j) = new_y;
end
end
imshow(final_img);
This is one solution for 'translation only' transformation.
I = imread('Lenna.png');
shiftX = 5; % shift columns
shiftY = 5; % shift rows
% Assigning empty matrix for result, expected to be shiftX-1 larger in rows and shiftY-1 larger in columns
nI = uint8( zeros(size(I,1)+shiftY-1, size(I,2)+shiftX-1, size(I,3));
% Translate
nI(shiftY:end, shiftX:end, :) = I;
imshow(nI)
Now the image will start from (x,y) = (5,5) instead of (1,1). Also note that in matlab image coordinate system, x and y axis start from upper left corner (documentation).
final_img:
You've defined "final_img" with new x and new y but you haven't replaced the zeros in the red/green/blue values. It's all black because of your initialisation filling the final_img with all zeros.
Maybe try this instead of what you've written:
%{
[X,map] = imread('name2.png');
figure(1);
% X should be 600 by 600
%Translate X however you wish, e.g.:
X = X +5;
%Verify that the colormap, map, is not empty, and convert
%the data in X to RGB and store as your final_img.
if ~isempty(map)
final_img = ind2rgb(X,map);
end
%}
I am also not sure if you want to be indexing img with just a single i without the the other dimensions like you have:
new_x = img(i) + 5;
?
For the problems in your specific code, I wrote in the comments some of them.
A short way to achieve image translation is by 2D convolution with a filter of zeros and just one 1, that will preserve the values of the image, but relocate them according to the size of the filter and the position of the 1 in it.
That seems you want to move the image but preserve the size of the total image, if I get it right. So:
r=3; c=5; % number of rows and columns to move
filt=zeros(r*2+1, c*2+1); filt(end)=1; % the filetr
img2=conv2(img,filt,'same'); % the translated image
Just for the example, lets translate "cameraman" with 20 rows and columns:
img=imread('cameraman.tif');
imshow(img)
r=20; c=20;
filt=zeros(r*2+1, c*2+1); filt(end)=1;
img2=conv2(img,filt,'same');
figure; imshow(img2,[])
Using the imfindcircles function in MATLAB to track circles in two images. I start with approximately a grid of circles which deforms. I am trying to sort the two column vector from imfindcircles into matrices so that neighbouring circles are neighbouring elements in the matrices. The first image the circles conform to a grid and the following code works:
[centXsort,IX] = sortrows(centres1,1); %sort by x
centYsort =zeros(289,2); %preallocate
for i = 1:17:289
[sortedY,IY] = sortrows(centXsort(i:i+16,:),2); %sort by y within individual column
centYsort(i:i+16,:) = sortedY;
end
cent1mat = reshape(centYsort,17,17,2); %reshape into centre matrices
This doesn't work for the second image as some of the circles overlap in the x or y direction, but neighbouring circles never overlap. This means that in the second set of matrices the neighbouring circles aren't neighbouring elements after sorting.
Is there a way to approximate a scatter of points into a matrix?
This answer doesn't work in every single case, but it seems good enough for situations where the points don't vary too wildly.
My idea is to start at the grid corners and work our way along the outside diagonals of the matrix, trying to "grab" the nearest points that seem like they fit into the grid-points based any surrounding points we've already captured.
You will need to provide:
The number of rows (rows) and columns (cols) in the grid.
Your data points P arranged in a N x 2 array, rescaled to the unit square on [0,1] x [0,1]. (I assume the you can do this through visual inspection of the corner points of your original data.)
A weight parameter edge_weight to tell the algorithm how much the border points should be attracted to the grid border. Some tests show that 3-5 or so are good values.
The code, with a test case included:
%// input parameters
rows = 11;
cols = 11;
edge_weight = 4;
%// function for getting squared errors between the points list P and a specific point pt
getErr =#(P,pt) sqrt( sum( bsxfun(#minus,P,pt(:)').^2, 2 ) ); %'
output_grid = zeros(rows,cols,2); %// output grid matrix
check_grid = zeros(rows,cols); %// matrix flagging the gridpoints we have covered
[ROW,COL] = meshgrid(... %// coordinate points of an "ideal grid"
linspace(0,1,rows),...
linspace(0,1,cols));
%// create a test case
G = [ROW(:),COL(:)]; %// the actual grid-points
noise_factor = 0.35; %// noise radius allowed
rn = noise_factor/rows;
cn = noise_factor/cols;
row_noise = -rn + 2*rn*rand(numel(ROW),1);
col_noise = -cn + 2*cn*rand(numel(ROW),1);
P = G + [row_noise,col_noise]; %// add noise to get points
%// MAIN LOOP
d = 0;
while ~isempty(P) %// while points remain...
d = d+1; %// increase diagonal depth (d=1 are the outer corners)
for ii = max(d-rows+1,1):min(d,rows)%// for every row number i...
i = ii;
j = d-i+1; %// on the dth diagonal, we have d=i+j-1
for c = 1:4 %// repeat for all 4 corners
if i<rows & j<cols & ~check_grid(i,j) %// check for out-of-bounds/repetitions
check_grid(i,j) = true; %// flag gridpoint
current_gridpoint = [ROW(i,j),COL(i,j)];
%// get error between all remaining points and the next gridpoint's neighbours
if i>1
errI = getErr(P,output_grid(i-1,j,:));
else
errI = edge_weight*getErr(P,current_gridpoint);
end
if check_grid(i+1,j)
errI = errI + edge_weight*getErr(P,current_gridpoint);
end
if j>1
errJ = getErr(P,output_grid(i,j-1,:));
else
errJ = edge_weight*getErr(P,current_gridpoint);
end
if check_grid(i,j+1)
errJ = errJ + edge_weight*getErr(P,current_gridpoint);
end
err = errI.^2 + errJ.^2;
%// find the point with minimal error, add it to the grid,
%// and delete it from the points list
[~,idx] = min(err);
output_grid(i,j,:) = permute( P(idx,:), [1 3 2] );
P(idx,:) = [];
end
%// rotate the grid 90 degrees and repeat for next corner
output_grid = cat(3, rot90(output_grid(:,:,1)), rot90(output_grid(:,:,2)));
check_grid = rot90(check_grid);
ROW = rot90(ROW);
COL = rot90(COL);
end
end
end
Code for plotting the resulting points with edges:
%// plotting code
figure(1); clf; hold on;
axis([-0.1 1.1 -0.1 1.1])
for i = 1:size(output_grid,1)
for j = 1:size(output_grid,2)
scatter(output_grid(i,j,1),output_grid(i,j,2),'b')
if i < size(output_grid,1)
plot( [output_grid(i,j,1),output_grid(i+1,j,1)],...
[output_grid(i,j,2),output_grid(i+1,j,2)],...
'r');
end
if j < size(output_grid,2)
plot( [output_grid(i,j,1),output_grid(i,j+1,1)],...
[output_grid(i,j,2),output_grid(i,j+1,2)],...
'r');
end
end
end
I've developed a solution, which works for my case but might not be as robust as required for some. It requires a known number of dots in a 'square' grid and a rough idea of the spacing between the dots. I find the 'AlphaShape' of the dots and all the points that lie along the edge. The edge vector is shifted to start at the minimum and then wrapped around a matrix with the corresponding points are discarded from the list of vertices. Probably not the best idea for large point clouds but good enough for me.
R = 50; % search radius
xy = centres2;
x = centres2(:,1);
y = centres2(:,2);
for i = 1:8
T = delaunay(xy); % delaunay
[~,r] = circumcenter(triangulation(T,x,y)); % circumcenters
T = T(r < R,:); % points within radius
B = freeBoundary(triangulation(T,x,y)); % find edge vertices
A = B(:,1);
EdgeList = [x(A) y(A) x(A)+y(A)]; % find point closest to origin and rotate vector
[~,I] = min(EdgeList);
EdgeList = circshift(EdgeList,-I(3)+1);
n = sqrt(length(xy)); % define zeros matrix
matX = zeros(n); % wrap x vector around zeros matrix
matX(1,1:n) = EdgeList(1:n,1);
matX(2:n-1,n) = EdgeList(n+1:(2*n)-2,1);
matX(n,n:-1:1) = EdgeList((2*n)-1:(3*n)-2,1);
matX(n-1:-1:2,1) = EdgeList((3*n)-1:(4*n)-4,1);
matY = zeros(n); % wrap y vector around zeros matrix
matY(1,1:n) = EdgeList(1:n,2);
matY(2:n-1,n) = EdgeList(n+1:(2*n)-2,2);
matY(n,n:-1:1) = EdgeList((2*n)-1:(3*n)-2,2);
matY(n-1:-1:2,1) = EdgeList((3*n)-1:(4*n)-4,2);
centreMatX(i:n+i-1,i:n+i-1) = matX; % paste into main matrix
centreMatY(i:n+i-1,i:n+i-1) = matY;
xy(B(:,1),:) = 0; % discard values
xy = xy(all(xy,2),:);
x = xy(:,1);
y = xy(:,2);
end
centreMatX(centreMatX == 0) = x;
centreMatY(centreMatY == 0) = y;