I'm working on an image processing project where i need to detect corners. But when i try to detect corners using corner function, it detects the small displacements as corners as shown.
I've tried with different thresholds from 0 to 0.24 and couldn't get food results.
imgskele = bwmorph(imgfill,'thin',Inf);
C = corner(imgspur, 'SensitivityFactor', 0.24);
figure; imshow(imgspur);
hold on;
plot(C(:,1), C(:,2),'bo','MarkerSize',10,'MarkerFaceColor','g');
hold off;
So i'm thinking of adjusting(redrawing) the line to make it straight line connecting those points
Edit 1:
Here are the full size original and output images:
The problem which you have is that the corner function is the Harris corner detector, which finds the corner of filled polygons.
Now a line can be approximated by a very thin polygon, certainly when pixelated, but that's not perfect as you notice here.
A more robust method is to use something like the Hough transform to find line features in the image. These lines will have intersections, some of which are approximately the corners you want. Others are fake intersections, because the Hough transform assumes lines and not line segments. You'll need to experiment a bit what you accept and what you reject. How rounded can a corner be, before you no longer call it a corner?
Related
As an input of my code, I need to have some positions on my picture: the positions are in pixels and the origin (0,0) is in the CORNER top left of my picture
The problem is that when I run my code which maps the positions on my picture, the origin shifts to the bottom left :
So my question is : how could I also shift my input (positions of my picture1) so that it is relevant with the code process?
Thank you for your help,
Aude
Adding an answer with a bit detail:
In computers, image processing etc it is the norm to have the (0,0) pixel in the top left corner. However, it is understandable that when you have x,y data, you'd want to plot it together with the image. Here some solutions:
imshow(image);
axis xy; % This line sets up the axis in a standard coordinate system
you can revert it with axis ij
Often, this is not enough. As imshow assumes that each pixel is in integer index position, and you may not have that. Maybe your data is in milimeters, or in any other arbitrary units. A solution to that is using imagesc
imagesc(img);
is equivalent to imashow(img);axis xy. Additionally, you can choose arbitrary matrices for pixel locations as imagesc(x,y,img);
Finally, you can flipud your data for plotting, but I suggest you do that inline with the plot, so you dont modify the data itself.
imshow(flipud(img))
With images you reverse the Y axis:
set(ax,'YDir','reverse');
That would depend on your code. Maybe you can do it on-the-fly so you'll get the desired output right away.
If not just flip the output. You could use flipud for that.
https://de.mathworks.com/help/matlab/ref/flipud.html
When determining points within polygons using MATLAB's inpolygon function, I find that the results are exactly correct for polygons drawn on linear axes but only approximately correct for polygons drawn on log-scale axes. Although my suspicions lean in favor of a MATLAB bug, it's possible I've overlooked something.
The following code reproduces the issue I have been experiencing with other data. The results are shown in the following image (the bottom set of panels are zoomed views of the top panels). One can appreciate that there are unlabeled points inside the polygon and labeled points outside the polygon, neither of which should occur, in the case of a polygon drawn on log-scale axes (right). In contrast, the polygon test is exact for polygons drawn on linear axes (left).
n=2E4;
x(:,1)=rand(n,1); y(:,1)=rand(n,1);
x(:,2)=lognrnd(0.5,0.25,n,1); y(:,2)=lognrnd(0.5,0.25,n,1);
for m=1:2
subplot(1,2,m);
scatter(x(:,m),y(:,m),'.'); hold on;
if(m==2)
set(gca,'xscale','log'); set(gca,'yscale','log');
end
p=impoly(gca);
pc=getPosition(p);
in=inpolygon(x(:,m),y(:,m),pc(:,1),pc(:,2));
scatter(x(in,m),y(in,m),20);
end
I think you missed something: A line in normal scale is not a line in log scale. Your polygons are not properly drawn in the log scale, as you draw 2 points and put them together with a straight line.
Look at the real polygon in log space:
close all
clear
n=2e4;
x(:,1)=rand(n,1); y(:,1)=rand(n,1);
x(:,2)=lognrnd(0.5,0.25,n,1); y(:,2)=lognrnd(0.5,0.25,n,1);
for m=1:2
subplot(1,2,m);
scatter(x(:,m),y(:,m),'.'); hold on;
if(m==2)
set(gca,'xscale','log'); set(gca,'yscale','log');
end
p=impoly(gca);
pc=getPosition(p);
% plot polygon
hold on
for ii=1:size(pc,1)-1
plot(linspace(pc(ii,1),pc(ii+1,1),100),linspace(pc(ii,2),pc(ii+1,2),100),'g')
end
plot(linspace(pc(end,1),pc(1,1),100),linspace(pc(end,2),pc(1,2),100),'g')
in=inpolygon(x(:,m),y(:,m),pc(:,1),pc(:,2));
scatter(x(in,m),y(in,m),20);
end
Look at this zoomed in result (click to enlarge):
This happens because the polygon is defined in euclidean space, and it is defined as points linked by lines. If you want to work in log space, things may get complicated. One way to numerically approximate it is the inverse of what I did for plotting. Create dense enough sampled straight line on log space, convert it to linear space, and define a high vertex polygon with the resulting points. Then use inpolygon.
My image is something like below:
I want to be able to draw 2 layers: (1) red line on top of 1st layer, but (2) blue line in the middle of 2nd layer
I am using OpenCV. but any languages/advice are welcomed.
You can do the following:
Small closing in order to reconnect the small separated components/patterns.
Small opening in order to remove the small isolated components/patterns.
Skeletonize (or median axis)
Pruning in order to remove the small branches.
You will then get a skeleton for each pattern. It will be close to the lines you want to draw. But it will be a little bit irregular, so you can interpolate it.
[EDIT] if you need the red line on top of the edge, a solution is to:
Extract the pattern contour
Keep only the pixel on top.
Algorithmically, it can be achieved doing this: for each X coordinate on the top border, go down the image vertically until you meet the first non-null pixel. If your image is NxM, you must have N pixels in your solution.
If you want to regularize/smooth the result, you have two solutions:
Transform the contour as a parametric function and smooth it.
Do an interpolation (spline?)
I have a small problem in smoothing a line surface.
The image is a result of edge detection after sobel processing.
It has an uneven surface, and the unit of bulges is one pixel.
Red circle parts are the bulges.
http://www.mathworks.com/help/matlab/creating_plots/smooth-contour-data-with-convolution-filter.html
The link I have tried, but the line width was increased too more.
I have to get a straight line with one pixel width.
How to clear up these bulges?
Many Thanks.
7/21 update:
Canny method can generate a detected image with one pixel.
The result of Canny edge detection:
The line was segmented 2 parts, the under part was shifted by one pixel.
I hope the line that can be considered a straight line rather than 2 lines when the line width is within 2~3 pixel.
With Dilate and Erosion, I tried to smooth the line that become a straight line
Canny > Dilate:
Canny > Dilate > Erosion:
The result of before and after are the same...
Could anyone give me an idea?
Many Thanks again.
If you are working with a simple 2-D, black-and-white image, stored as a 0/1 array, and you guarantee there will always be a straight line all the way from top to bottom, then this may help -
% recreate scenario
A = zeros(100,50);
A(:,25) = 1;
A([30:40,80:85],24)=1;
A([20:35,70:90],26)=1;
% a rude way
S = sum(A,1);
B = repmat(S==max(S),100,1);
imshow(B)
Maybe an approach similar to Canny edge detection could be the solution you are searching for. The Canny edge detector uses non maximum suppression, meaning that the edges are formed only by pixels that have the maximum gradient between their neighbours, resulting in many occasions in one-pixel-width edges.
What coding techniques would allow me to to differentiate between circles, rectangles, and triangles in black and white image bitmaps?
You could train an Artificial Neural Network to classify the shapes :P
If noise is low enough to extract curves, approximations can be used: for each shape select parameters giving least error (he method of least squares may help here) and then compare these errors...
If the image is noisy, I would consider Hough transform - it may be used to detect shapes with small count of parameters, like circle (harder for rectangles and triangles).
just an idea off of the top of my head: scan the (pixel) image line-by-line, pixel-by-pixel. If you encounter the first white pixel (assuming it has a black background) you keep it's position as a starting point and look at the eight pixels surrounding it in every direction for the next white pixel. If you find an adjacent second pixel you can establish a directional vector between those two pixels.
Now repeat this until the direction of your vector changes (or the change is above a certain threshold). Keep the last point before the change as the endpoint of your first line and repeat the process for the next line.
Then calculate the angle between the two lines and store it. Now trace the third line. Calculate the angle between the 2nd and 3rd line as well.
If both angles are rectangular you probably found a rectangle, otherwise you probably found a triangle. If you can't find any straight line you could conclude that you found a circle.
I know the algorithm is a bit sketchy but I think (with some refinement) it could work if your image's quality is not too bad (too much noise, gaps in the lines etc.).
You are looking for the Hough Transform. For an implementation, try the AForge.NET framework. It includes circle and line hough transformations.