Is there any way to "approximate" the rest of a circle in OpenCV? - c++

I am trying to detect circles in some pictures but the circles aren't always perfect. This makes houghCircles very impractical to use because it seems to only support almost perfect circles. So now i am searching for a way to kind of "fix" my circles.
for reproduction purposes:
First i threshold the picture to get a binary picutre:
cv::threshold(input, output, threshvalue, 1, cv::THRESH_BINARY_INV);
After thresholding i detect the Hough Circles with :
std::vector<cv::Vec3f> circles;
HoughCircles(binarypicture,circles,cv::HOUGH_GRADIENT,1,100,30,26,45);

Related

Image processing : Improved thresholding?

I would like to apply a rotation on image of scanned book.
I use FindContours and approxPolyDP to get the corners of the book and for that I need a perfect white square. Only, when I apply a simple threeshold:
threshold(imgGrayScale, three, 1, 255, THRESH_BINARY);
on my input image I have still some points here and there. Thresholding it is the good solution to get a full perfect white square? Maybe Segmentation would be a better solution?
Summary of my post :
http://imgur.com/FWp28rr

OpenCV Adaptive Thresholding a HSV image

We (my group and I) want to be able to track a hand (well the index fingertip mostly). The hand is basically the same colour as the face in the picture, but as you can see, so is a lot of the noise we get. It works very well with a black "screen" behind the hand.
Now the problem is that Adaptive thresholding is useful only on Grayscale images, and as such would not detect the hand very well.
I've tried googling HSV Adaptive Thresholding but no luck, so I figured stackoverflow had some great ideas.
EDIT: The current HSV -> Binary threshold:
inRange(hsvx, Scalar(0, 50, 0), Scalar(20, 150, 255), bina);
I suggest you use a color histogramming for your tracking. Camshift is doing it for example to good success.
There is camshift sample code in OpenCV.
See http://docs.opencv.org/master/db/df8/tutorial_py_meanshift.html (very brief explanation)
or https://github.com/Itseez/opencv/blob/master/samples/cpp/camshiftdemo.cpp (code sample)
If you want to go with your thresholding, you are already proper about not thresholding the V channel. I would still suggest to do separate adaptive thresholding on H and S.
I would suggest you using a histogram backprojection algorithm.
Back Projection is a way of recording how well the pixels of a given image fit the distribution of pixels in a histogram model. You can specify the histogram model by using manually selected set of hand-pixels.
This algorithm outputs an image where each pixel has the value of likelihood the color of this pixel is a color of the skin (is similar to the skin). You can then specify a likelihood threshold to adjust the performance.
It will let you find the skin-colured areas in the image.
For details see:
http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/back_projection/back_projection.html
http://docs.opencv.org/master/dc/df6/tutorial_py_histogram_backprojection.html#gsc.tab=0

Detecting Many Small Circles in Close Proximity with cv::HoughCircles()

I am trying to detect a large number of small circles that are in relatively close proximity to one another (only about 20 pixels apart) using OpenCV. I have managed to create this mask using cv::inRange() and cv::Canny().
Original Image
Mask
However, when I use cv::HoughCircles() only some of the circles are being detected accurately. Currently, I am using cv::HoughCircles() with the following parameters:
cv::HoughCircles(mat, circles, CV_HOUGH_GRADIENT, 2, mat.rows / 256, 100, 8, 2, 8);
Is this method not effective enough to detect circles that are this small and close together, or do I simply need to modify the parameters of cv::HoughCircles()?
Also, it would be useful to get rid of the "noise" surrounding the array of circles in the middle of the mask because some "false circles" are being detected around the edges of the mask. Is there a simple way to do this?
Get rid of the noise :
If you can make sure to always have the same environment parameters (e.g. distance from the circle, luminosity...), then you could mask your image just after the Canny edge detection, with cvAnd; here is what the mask would look like :
Hough circles detection :
Now, about HoughCircle. First, this function performs its own Canny edge detection. You are doing one too just before the call to HoughCircle. It may have an impact on the shapes of your circles, because of the way Canny works (i.e. intensity gradient on binary image...).
Speaking about the shape of your circles, just below is a close-up of what your "circles" look like; I would have been very impressed if HoughCircle actually did detect all or even just some of those. It can't give anything good in Hough space. Just to make sure, set the last two parameters to 0 (min/max radius), and try to lower the minimum distance between centers. But honestly, I think you need to find another approach to your problem.
[EDIT]
A possible approach would be to perform connected component labeling (e.g. blob detection). As far as I know it is not possible to do this simply with OpenCV alone, you will need something like cvblob, which is a very good OpenCV-based blob library. In particular, you might be interested in cvCentroid(CvBlob *blob).
Cheers
Hum, do you really need to detect them as circles? (as opposed to model them as circles).
If this is some kind of calibration pattern, and you are only interested in estimating the image positions of the centers, It may be a lot more efficient to detect them as point-like features first, then process each detected one individually - e.g. fitting a circle to a blob of white pixels in the neighborhood of each detected feature.

OpenCV - find or access shape contour not surrounded by bg, only separated by an outline

I've been trying to find the contour of a single shape in a very plain background using OpenCV's findContour (I'd like to use the C++ syntax). However, it keeps on making its outline a contour and not the shape itself. I'm thinking it's because of the white edge resulted from Canny which doesn't make the shape closed.
Case A: Shape is by the image's edge
(This is not the actual input image but a simpler input image to illustrate this problem.)
Case B: Background surrounds the shape
There are the main functions I used:
findContours( grayImage, contours, hierarchy, RETR_LIST,CHAIN_APPROX_SIMPLE);
approxPolyDP(Mat(contours.at(largestContourIndex)),poly,3,true);
drawContours(output, contours, largestContourIndex, RGB(250,0,100), -1, 8, hierarchy, 0, Point() );
EDIT: Skipping edge detection gives the contour I need but I need to have the best contour approximate I can get.
Thanks in advance.
Did you try playing around with morphology operations?
If your basic problem is that the contour you're getting is on the outside of the object instead of the inside, and especially if your object are made out of so clear-cut and mostly regular shapes, than morphology might help.
I know OpenCV has implementations of dilation and erosion, as well as opening and closing operations. A very simple approach that might work in your situation is just eroding the shape a little bit (maybe 1-2-3 iterations) and then doing exactly what you are doing already. Hopefully, then, you'll get the outer contours of the eroded shape, that should actually be the inner contours of the original shape.
I think OpenCV actually implements even some more complex morphology, but as always, try the simple stuff first :D
It seems to me that the contour you are looking for is probably detected, but you are not using it. Instead you are using the largest contour. Try plotting all found contours one by one and see if it's in there.
If it is not, try inverting the canny image and repeating the process.
I still haven't found the reason why I can't get the shape contour but I found a workaround. After doing erosion and dilation, I basically have to draw a border or a rectangle on the outermost pixels of the input image for the background to surround the shape, ...
rectangle(input,Point(0,0),Point(input.cols-1,input.rows-1),Scalar(0,0,0),1,8,0);
... hence, letting Canny draw a closed shape outline and giving me the shape contour I want. I am still trying to successfully invert Canny's output like what #dvhamme has suggested but it's still giving me errors. It would be better if somebody points out how to properly get or access the shape contour but thanks everyone for the help.

How to find contours in an image in OpenCV?

I need to find all contours in an image. I know the whole findcontours () and drawContours () thing, but its using the Canny edge detector that I am having trouble with. To use find contours, you either need to use canny edge detection or threshold the image. I cannot threshold the image because this would result in several edges getting blurred out ("merging" of the edges). So I decided to use Canny Edge detection. However, when I do use it instead of getting perfect edges, I get a variety of lines with gaps in them. This prevents me from getting good contours For example instead of getting the edges of a square, I would get 4 separate lines separated by small gaps resulting in me getting 4 contours instead of one. I tried dilating, opening, closing, Gaussian blurring and basically every morphological operator, but none of these are doing the job. Some do not merge the lines, while some merge the lines with non-relevant lines too. So I was wondering does anyone have a solution on how I can get actual contours from Canny Edge detection, or if not does someone have any alternatives to get all the contours from an image?
make blob, then contours come with it. :)
http://code.google.com/p/cvblob/