Detect non-closed contour on opencv - opencv

I'm doing computer vision project for automatic card detection.
I need to separate the card from the background. I have applied the canny edge detection, using automatic parameter settings from this
Automatic calculation of low and high thresholds for the Canny operation in opencv
The result is excellent. However, sometimes the canny is not perfect like this
I have applied cvFindContour to detect the box. However, due to "hole" on the upper side, opencv failed to detect the contour.
How do I tune the cvFindContour to detect the contour or should I tune the canny edge instead?

There are multiple possible solutions.
The simplest one may be:
if FindContours does not find a closed contour, repeat the canny filter with a slightly decreased low_threshold, until you find a closed contour. If the closed contour has roughly the right size and shape, it is a card. The answer linked by Haris explains how to check whether a contour is closed
Another rather simple solution:
Don't apply Canny to the image at all. Execute findContours on the otsu thresholded image. Optionally use morphological opening and closing on the thresholded image to remove noise before findContours
FindContours does not need an edge image, it is usually executed with a thresholded image. I don't know your source image, so I cannot say how good this would work, but you would definitely avoid the problem of holes in the shape.
If the source image does not allow this, then the following may help:
use watershed to separate the card from the background. Use a high threshold to get some seed pixels that are definitely foreground and a low threshold to get pixels that are definitely background, then grow those two seeds using cv:watershed().
If the background in that image is the same color as the card, then the previous two methods may not work so well. In that case, your best bet may be the solution suggested by Micka:
use hough transform to find the 4 most prominent lines in the image. Form a rectangle with these 4 lines.

Related

Any way to get strongest edge local to a contour line using cv2 or scikit-image?

I am working on accurately segmenting objects from an image.
I have found contour lines by using a simple rectangular prism in HSV space as a color filter (followed by some morphological operations on the resulting mask to clear up noise). I found this approach to be better than applying canny edge detection to the whole image as that just picked up a lot of other edges I don't care about.
Is there a way to go about refining the contour line I have extracted such that it clips to the strongest local edge kind of like Adobe Photoshop's smart cropping utility?
Here's an image of what I mean
You can see a boundary between the sky blue and the gray. The dark blue is a drawn on contour. I'd like to somehow clip this to the nearby edge. It also looks like there are other lines in the grey region, so I think the algorithm should do some sort of more globalish optimisation to ensure that the "clipping" action doesn't jump randomly between my boundary of interest and the nearby lines.
Here are some ideas to try:
Morphological snakes: https://scikit-image.org/docs/dev/auto_examples/segmentation/plot_morphsnakes.html
Active contours: https://scikit-image.org/docs/dev/auto_examples/edges/plot_active_contours.html
Whatever livewire is doing under the hood: https://github.com/PyIFT/livewire-gui
Based on this comment, the last one is the most useful.

How to get Vector data in skeletonization?

i am using opencv to track the edge of a hand on an image. Using skin color is not that reliable so we can't use contour. Using Canny edge detection match what we need because it can get most of the outline correctly. Now i want to make the information to vector so that i can improve it in the vector way. I can't use HoughLinesP because the lines are usually not straight. Dilating it gives lots of unwant random lines. I can do thinning but i don't know what next step i should do. the thinned image is still image. I need the vector data. So how do i do it?

Are there other methods to detect circles apart from HoughCircles

I am trying to detect circular road signs and I have some issues.
The HoughCircles function detects circles in a gray image, however with the same parameters but the image binarized (the circle is still perfectly visible) it does not detect any circle. I do not why it fails a lot with a binarized image. Any ideas why I have this issue with binary images?
To try to correct that I set the dp parameter to 2 and changed the threshold. In the binary image I now detect circles, but it also gives me a lot of false positives. I do not understand what the dp parameter is, or how to use it.
If there is no way to make it work, I would like to know if there is any other way of detecting circles in an image.
Hough generally works well with bad data - partial or obscured circles and noise.
But it is sensitive to the tuning parameters (max, min diameter, number of votes for a result).
Typically you could run hough to find all possible circles and then examine each possible circle by eg checking distance from center to points on the circumference. Or you could look at found circle diameters and then refine your diameter/vote bins, especially if this is a video stream and you expect the circles to be similar in the future.

Alternative for Threshold in opencv

I am using threshold in Opencv to find the contours. My input is a hand image. Sometimes the threshold is not good so I couldnt find the contours.
I have applied the below preprocessing steps
1. Grabcut
cv::grabCut(image, result,rectangle,bgModel,fgModel, 3,cv::GC_INIT_WITH_RECT);
gray Scale conversion
cvtColor(handMat, handMat, CV_BGR2GRAY);
meadianblur
medianBlur(handMat, handMat, MEDIAN_BLUR_K);
I used the below code to find threshold
threshold( handMat, handMat, 141, 255, THRESH_BINARY||CV_THRESH_OTSU );
Sometimes I get good output and sometimes the threshold output is not good. I have attached the two output images.
Is there any other way than threshold from which contours can be found?
Good threshold Output:
Bad threshold Output
Have you tried an adaptive threshold? A single value of threshold rarely works in real life application. Another truism - threshold is a non-linear operation and hence non-stable. Gradient on the other hand is linear so you may want to find a contour by tracking the gradient if your background is smooth and solid color. Gradient is also more reliable during illumination changes or shadows than thresholding.
Grab-cut, by the way, uses color information to improve segmentation on the boundary when you already found 90% or so of the segment, so it is a post processing step. Also your initialization of grab cut with rectangle lets in a lot of contamination from background colors. Instead of rectangle use a mask where you mark as GC_FGD deep inside your initial segment where you are sure the hand is; mark as GC_BGD far outside your segment where you sure background is; mark GC_PR_FGD or probably foreground everywhere else - this is what will be refined by grab cut. to sum up - your initialization of grab cut will look like a russian doll with three layers indicating foreground (gray), probably foreground (white) and background (balck). You can use dilate and erode to create these layers, see below
Overall my suggestion is to define what you want to do first. Are you looking for contours of arbitrary objects on arbitrary moving background? If you are looking for a contour of a hand to find fingers on relatively uniform background I would:
1. use connected components or MSER to segment out a hand. Possibly improve results with grab cut initialized with the conservative mask and not rectangle!
2. use convexity defects to find fingers if this is your goal;
One issue is to try to find contours without binarizing the image.
If your input is in color, you can try to change color space in order to enhance the difference between the hand and the background.
Otsu try to find an optimal threshold, you can also try to set it manually but Otsu is useful because if the illumination change, the threshold will adapt automatically.
There are also many other kind of binarization : Sauvola, Bradley, Niblack, Kasar... but Otsu is simple, and work well. I suggest you to do preprocessing or postprocessing if you want to improve the binarization result.

Get edge co-ordinates after edge detection (Canny)

I have been working with OpenCV for a fairly short time, and have performed Canny Edge Detection on an image, and also performed dilation after that to further separate the object (in my case a square) from the background.
My problem, now is to identify graspable regions in 2D using an algorithm that requires me to handle co-ordinates of the points in those edges. Is there any way I can use OpenCV to get the co-ordinates of the corners so I can find the equation of the lines forming the edge of the square? I know the size of the square. My problem involves 2D co-ordinate geometry, and hence the need for co-ordinates.
I can provide the image after edge detection and dilation if need be. Help would be appreciated a lot.
Just offering a second method - not guaranteed to work.
Step 1: extract connected component and their contours. This can be applied after the Canny Edge Detection step.
FindContours
Step 2: If the contours are fairly good approximation of a square, you can use their bounding box directly.
BoundingRect - if the rectangles are always upright (not rotated)
MinAreaRect - if the rectangles are rotated.
The reason for the disclaimer is that it only works on very clean results, without any broken edges or gaps in the Canny edges, etc. If you need a more robust way of finding rectangles, Hough transform will be necessary.
You could use the corner detectors provided in OpenCV like Harris or Corner Eigenvalues. Here's an example of that along with full-fledged code.
In case other features are also throwing up corners you may need to go in for connected component analysis.

Resources