Detect not complete/perfect triangles - c++

I am tryng to detect traffic signs by their colour and shape, i have the binary image from de colour segmentation and i try to detect triangles in it, by unless all the sides of the triangle are complete y doesnt work,
in this image for example it does not detect any triangle
the code i am using is this:
vector<Point> approx;
findContours(copia,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
vector<Rect_ <int> > boundRect( contours.size() );
vector<Rect_ <int> > boundRect_( contours.size() );
for(size_t i=0; i<contours.size();i++)
{
approxPolyDP(Mat(contours[i]), approx,arcLength(Mat(contours[i]), true)*0.02, true);
if (approx.size() == 3 &&fabs(contourArea(Mat(approx))) > 300 && isContourConvex(Mat(approx)))
drawContours(capture->image,contours,i,Scalar(0,255,0));
It is not a problem of the cotourArea, i have no problem detecting complete triangles. I do not know if i could do something to detect that kind of "not complete triangles" or i would have to do something to complete the triangle so that i could detect them. In either case i am a bit lost
Thank you for your help
EDIT: i forgot to upload the image

Actually, opencv side of a triangle maybe difficult in terms of vision but I would suggest some method that may help you achieve.
1) Use Corner detector
(OpenCV Canny) to detector all corner in the binary image. I would say use Morphological Operations (Dilate and Errode) as a means to reduce noise instead of blurring or non-max suppression. Next Use the extreme points, and connect it to form Triangles. Because there will be perhaps many corners you can try fitting all the points and select the maximum Fit. You may also use delaunay triangulation to find the triangle to the points.
2) Using Curvature Info.
Since one edge of the triangle is missing, you can use the 2 edges to compute the curvature of the circumscribing contour. Again here Morphological Operations (Dilate and Errode) can be useful. Than you can select points where curvature (Computing the Curvature of Binary Image Contour) change drastically as extreme point as vertex and fit lines to get approximation to the traiangle. If you image is less noisely you can use Convex Hull to get the approximation.
3) RANSAC Fitting
You may also use Fitting method to approximate the triangle by using variants of triangles and fit it to the 2 estimated edges on the binary image.

Topic is old - but might help others.
I had same issue but I dealt with it using dilate() function on input image (it might require 2-3 iterations if triangle has big gap). It is not the best solution but at the moment seems to be the easiest one.

Related

Remove contour defects [OpenCV]

I want to generalize this question: How to crop away convexity defects.
Situation described there is clear to me but I have more complex situation: I have a contour which can have not only convex, but a concave defects:
Blue is the contour I have and red is a rectangle I want - it can be rotated rectangle in general, so I need 4-point rectangular contour with area is as close as possible to the given contour. I'm looking for algorithm on how this transformation function could be implemented and it would be nice if it will be illustrated with code.
My idea would be to perform a Hough transform on the contour and choose the top 4 most prominent lines as the edges of the rectangle.
You should draw the contour as a b&w image and pass that to HoughLines. It will return a vector of (r, theta) pairs, which encode the detected lines in polar coordinates. See this example for how to convert them back to cartesian coordinates.
The lines will be ordered by decreasing number of "votes" (i.e. the sum of pixel intensities along the line).
Note that HoughLinesP is less suitable for the problem at hand, because it returns line segments, not lines.
The approach from the linked answer can only handle convexity defects based on deviation from the convex hull, I don't think you can use the opposite approach to remove 'concavity defects' (which grow the convex hull and make other features the defects).
You could try the following:
Run the solution from the linked answer to remove convex defects
On the resulting feature, iteratively call cv::ApproxPoly with varying accuracy parameter (e.g. 0.0, 0.5, 1.0...) until it approximates to a 4 sided shape.

Detect ball/circle in OpenCV (C++)

I am trying to detect a ball in an filtered image.
In this image I've already removed the stuff that can't be part of the object.
Of course I tried the HoughCircle function, but I did not get the expected output.
Either it didn't find the ball or there were too many circles detected.
The problem is that the ball isn't completly round.
Screenshots:
I had the idea that it could work, if I identify single objects, calculate their center and check whether the radius is about the same in different directions.
But it would be nice if it detect the ball also if he isn't completely visible.
And with that method I can't detect semi-circles or something like that.
EDIT: These images are from a video stream (real time).
What other method could I try?
Looks like you've used difference imaging or something similar to obtain the images you have..? Instead of looking for circles, look for a more generic loop. Suggestions:
Separate all connected components.
For every connected component -
Walk around the contour and collect all contour pixels in a list
Suggestion 1: Use least squares to fit an ellipse to the contour points
Suggestion 2: Study the curvature of every contour pixel and check if it fits a circle or ellipse. This check may be done by computing a histogram of edge orientations for the contour pixels, or by checking the gradients of orienations from contour pixel to contour pixel. In the second case, for a circle or ellipse, the gradients should be almost uniform (ask me if this isn't very clear).
Apply constraints on perimeter, area, lengths of major and minor axes, etc. of the ellipse or loop. Collect these properties as features.
You can either use hard-coded heuristics/thresholds to classify a set of features as ball/non-ball, or use a machine learning algorithm. I would first keep it simple and simply use thresholds obtained after studying some images.
Hope this helps.

Edge detection / angle

I can successfully threshold images and find edges in an image. What I am struggling with is trying to extract the angle of the black edges accurately.
I am currently taking the extreme points of the black edge and calculating the angle with the atan2 function, but because of aliasing, depending on the point you choose the angle can come out with some degree of variation. Is there a reliable programmable way of choosing the points to calculate the angle from?
Example image:
For example, the Gimp Measure tool angle at 3.12°,
If you're writing your own library, then creating a robust solution for this problem will allow you to develop several independent chunks of code that you can string together to solve other problems, too. I'll assume that you want to find the corners of the checkerboard under arbitrary rotation, under varying lighting conditions, in the presence of image noise, with a little nonlinear pincushion/barrel distortion, and so on.
Although there are simple kernel-based techniques to find whole pixels as edge pixels, when working with filled polygons you'll want to favor algorithms that can find edges with sub-pixel accuracy so that you can perform accurate line fits. Even though the gradient from dark square to white square crosses several pixels, the "true" edge will be found at some sub-pixel point, and very likely not the point you'd guess by manually clicking.
I tried to provide a simple summary of edge finding in this older SO post:
what is the relationship between image edges and gradient?
For problems like yours, a robust solution is to find edge points along the dark-to-light transitions with sub-pixel accuracy, then fit lines to the edge points, and use the line angles. If you are processing a true camera image, and if there is an uncorrected radial distortion in the image, then there are some potential problems with measurement accuracy, but we'll ignore those.
If you want to find an accurate fit for an edge, then it'd be great to scan for sub-pixel edges in a direction perpendicular to that edge. That presupposes that we have some reasonable estimate of the edge direction to begin with. We can first find a rough estimate of the edge orientation, then perform an accurate line fit.
The algorithm below may appear to have too many steps, but my purpose is point out how to provide a robust solution.
Perform a few iterations of erosion on black pixels to separate the black boxes from one another.
Run a connected components algorithm (blob-finding algorithm) to find the eroded black squares.
Identify the center (x,y) point of each eroded square as well as the (x,y) end points defining the major and minor axes.
Maintain the data for each square in a structure that has the total area in pixels, the center (x,y) point, the (x,y) points of the major and minor axes, etc.
As needed, eliminate all components (blobs) that are too small. For example, you would want to exclude all "salt and pepper" noise blobs. You might also temporarily ignore checkboard squares that are cut off by the image edges--we can return to those later.
Then you'll loop through your list of blobs and do the following for each blob:
Determine the direction roughly perpendicular to the edges of the checkerboard square. How you accomplish this depends in part on what data you calculate when you run your connected components algorithm. In a general-purpose image processing library, a standard connected components algorithm will determine dozens of properties and measurements for each individual blob: area, roundness, major axis direction, minor axis direction, end points of the major and minor axis, etc. For rectangular figures, it can be sufficient to calculate the topmost, leftmost, rightmost, and bottommost points, as these will define the four corners.
Generate edge scans in the direction roughly perpendicular to the edges. These must be performed on the original, unmodified image. This generally assumes you have bilinear interpolation implemented to find the grayscale values of sub-pixel (x,y) points such as (100.35, 25.72) since your scan lines won't fall exactly on whole pixels.
Use a sub-pixel edge point finding technique. In general, you'll perform a curve fit to the edge points in the direction of the scan, then find the real-valued (x,y) point at maximum gradient. That's the edge point.
Store all sub-pixel edge points in a list/array/collection.
Generate line fits for the edge points. These can use Hough, RANSAC, least squares, or other techniques.
From the line equations for each of your four line fits, calculate the line angle.
That algorithm finds the angles independently for each black checkerboard square. It may be overkill for this one application, but if you're developing a library maybe it'll give you some ideas about what sub-algorithms to implement and how to structure them. For example, the algorithm would rely on implementations of these techniques:
Image morphology (e.g. erode, dilate, close, open, ...)
Kernel operations to implement morphology
Thresholding to binarize an image -- the Otsu method is worth checking out
Connected components algorithm (a.k.a blob finding, or the OpenCV contours function)
Data structure for blob
Moment calculations for blob data
Bilinear interpolation to find sub-pixel (x,y) values
A linear ray-scanning technique to find (x,y) gray values along a specific direction (which will also rely on bilinear interpolation)
A curve fitting technique and means to determine steepest tangent to find edge points
Robust line fit technique: Hough, RANSAC, and/or least squares
Data structure for line equation, related functions
All that said, if you're willing to settle for a slight loss of accuracy, and if you know that the image does not suffer from radial distortion, etc., and if you just need to find the angle of the parallel lines defined by all checkboard edges, then you might try..
Simple kernel-based edge point finding technique (Laplacian on Gaussian-smoothed image)
Hough line fit to edge points
Choose the two line fits with the greatest number of votes, which should be one set of horizontal-ish lines and the other set of vertical-ish lines
There are also other techniques that are less accurate but easier to implement:
Use a kernel-based corner-finding operator
Find the angles between corner points.
And so on and so on. As you're developing your library and creating robust implementations of standalone functions that you can string together to create application-specific solutions, you're likely to find that robust solutions rely on more steps than you would have guessed, but it'll also be more clear what the failure mode will be at each incremental step, and how to address that failure mode.
Can I ask, what C++ library are you using to code this?
Jerry is right, if you actually apply a threshold to the image it would be in 2bit, black OR white. What you may have applied is a kind of limiter instead.
You can make a threshold function (if you're coding the image processing yourself) by applying the limiter you may have been using and then turning all non-white pixels black. If you have the right settings, the squares should be isolated and you will be able to calculate the angle.
Once this is done you can use a path finding algorithm to find some edge, any edge will do. If you find a more or less straight path, you can use the extreme points as you are doing now to determine the angle. Since the checker-board rotation is only relevant within 90 degrees, your angle should be modulo 90 degrees or pi over 2 radians.
I'm not sure it's (anywhere close to) the right answer, but my immediate reaction would be to threshold twice: once where anything but black is treated as white, and once where anything but white is treated as black.
Find the angle for each, then interpolate between the two angles.
Your problem have few solutions but all have one very important issue which you seem to neglect. Note: When you are trying to make geometrical calculation in the image, the points you use must be as far as possible one from the other. You are taking 2 points inside a single square. Those points are very close one to another, so a slight error in pixel location of of the points leads to a large error in the angle. Why do you use only a single square, when you have many squares in the image?
Here are few solutions:
Find the line angle of every square. You have at least 9 squares in the image, 4 lines in each square which give you total of 36 angles (18 will be roughly at 3[deg] and 18 will be ~93[deg]). Remove the 90[degrees] and you get 36 different measurements of the angle. Sort them and take the average of the middle 30 (disregarding the lower 3 and higher 3 measurements). This will give you an accurate result
Second solution, find the left extreme point of the leftmost square and the right extreme point of the rightmost square. Now calculate the angle between them. The result will be much more accurate because the points are far away.
A third algorithm which will give you accurate results because it doesn't involve finding any points and no need for thresholding. Just smooth the image, calculate gradients in X and Y directions (gx,gy), calculate the angle of the gradient in each pixel atan(gy,gx) and make histogram of the angles. You will have 2 significant peaks near the 3[deg] and 93[deg]. Just find the peaks by searching the maximum in the histogram. This will work even if you have a lot of noise in the image, even with antialising and jpg artifacts, and even if you have other drawings on the image. But remember, you must smooth the image a lot before calculating the derivatives.

OpenCV 'Almost' Closed contours

I'm trying to extract the cube from the image (looks like a square...). I've used canny and dilate to get the edges and remove the noise.
I'm not even sure if it is possible to get the square out in a robust way.
Advice appreciated!
Thanks.
It's not excessively hard.
Sort all edges by direction. Look for a pair of edges in one direction with another pair 90 degrees rotated. Check for rough proximity. If so, they probably form a rectangle. Check the edge distances to pick the squares from the rectangles, and to discard small squares. Check if you have sufficiently large parts of the edge to be convinced the entire edge must exist. An edge might even be broken in 2. Check if the 4 edges now found delimit an area that is sufficiently uniform.
The last bit is a bit tricky. That's domain knowlegde. Could there be other objects inside the square, and could they touch or overlap the edges of the square?
You can utilize color information and kmeans clustering as explained in the link.
As long as target object color differs from the background, the pixels of the square object can be detected accurately.

Detecting a cross in an image with OpenCV

I'm trying to detect a shape (a cross) in my input video stream with the help of OpenCV. Currently I'm thresholding to get a binary image of my cross which works pretty good. Unfortunately my algorithm to decide whether the extracted blob is a cross or not doesn't perform very good. As you can see in the image below, not all corners are detected under certain perspectives.
I'm using findContours() and approxPolyDP() to get an approximation of my contour. If I'm detecting 12 corners / vertices in this approximated curve, the blob is assumed to be a cross.
Is there any better way to solve this problem? I thought about SIFT, but the algorithm has to perform in real-time and I read that SIFT is not really suitable for real-time.
I have a couple of suggestions that might provide some interesting results although I am not certain about either.
If the cross is always near the center of your image and always lies on a planar surface you could try to find a homography between the camera and the plane upon which the cross lies. This would enable you to transform a sample image of the cross (at a selection of different in plane rotations) to the coordinate system of the visualized cross. You could then generate templates which you could match to the image. You could do some simple pixel agreement tests to determine if you have a match.
Alternatively you could try to train a Haar-based classifier to recognize the cross. This type of classifier is often used in face detection and detects oriented edges in images, classifying faces by the relative positions of several oriented edges. It has good classification accuracy on faces and is extremely fast. Although I cannot vouch for its accuracy in this particular situation it might provide some good results for simple shapes such as a cross.
Computing the convex hull and then taking advantage of the convexity defects might work.
All crosses should have four convexity defects, making up four sets of two points, or four vectors. Furthermore, if your shape was a cross then these four vectors will have two pairs of supplementary angles.