I'm trying to detect shapes with a specific color, using openCV.
The first thing i'm trying to do, is to detect circles in an image.
I'm able to detect the circles, using houghCircles, with this function call:
HoughCircles(gray, c, CV_HOUGH_GRADIENT, 1.5, gray.rows / 10, 200, 100, 0, 0);
Now i'm trying to detect the circles with the specific color.
I'm doing this using the inRange function, which returns a 8-bit, single-channel image.
This function is able to filter only the given color out of the image. I.e. yellow.
But when i pass the returned image in to the houghCircles function, it's returning no circles.
There are no compilation errors.
I already tried to change some of the parameters of houghCircles, but i'm not able to detect the circle.
This is an example of the image that inRange is returning:
Grayscale image
What parameters do i need to use, to detect the circle in that image?
Thanks in advance,
Peter
By doing some playing around with your image, I have found a set of parameters that work.
HoughCircles(shapes, circles, CV_HOUGH_GRADIENT, 1, shapes.rows / 4, 400, 20, 0, 0);
I doubt these are ideal parameters, and I strongly advise you to go and build your own app for changing function parameters - there are plenty of examples of simple slider-based apps in the OpenCV docs which you can use to play around with parameters until you hit upon something that works. This one, for example, is a demo for Hough Circles.
Additionally, you may not be using the best tool for the job. By using contours, you should be able to detect and classify a whole bunch of different shapes, not just circles. This tutorial is very close to what you're trying to do and probably worth a read.
Related
I've been stuck on this for a few days now, maybe someone will be able to help me here.
I'm using OpenCV C++ API to perform some basic image processing. I have a step where I want to blur my image and specify BORDER_WRAPas my border type :
cv::blur(img, img, cv::Size(3, 3), cv::Point(-1, -1), cv::BORDER_WRAP);
But when executing my code, I get the following error:
OpenCV Error: Assertion failed (columnBorderType != BORDER_WRAP)
However, everything works fine when I use other border types, (BORDER_REFLECT for example), but I need BORDER_WRAP
Things seem to work if I use copyMakeBorder(img, img, 1, 1, 1, 1, cv::BORDER_WRAP) first on my image, blur this new image and then crop it back to the size of the original one, but still I can't figure out why my first try doesn't work.
Anyone knows how I can solve this ?
You can't do this. BORDER_WRAP is not accepted by all functions - it's valid just for a few of them and, as the assertion failure confirms, cv::blur is not one of them..
But as you've already found out yourself, you can first use cv::copyMakeBorder, blur this new image and crop it back to the size of the original.
I'm trying to create a generic function which always finds my 3 color balls. (Red, yellow and white). I spend a lot of time to search a solution, and it's pretty hard...
For the moment, first, I use the Canny filter (I use the Otsu method to determine the lower and highter parameter) and I call the Hough Circle method by incrementing param2 until I find 3 circles.
while (!findCircles){
Imgproc.HoughCircles(hough, circles, Imgproc.CV_HOUGH_GRADIENT, 1, 100, 200, low, 20, 100); //find3Circles = true;
if (circles.cols() == 3){
findCircles = true;
}
low++;
}
It doesn't work very well...
If someone vote up for my question, i could post images (i have no enough points...) Please, if someone found the solution, it would be nice to tell me.
I think that you should base you method on finding colors, not shapes or at least you should stary with finding colors and then find shapes. Here there is good(it uses old OpenCV API, but everything else is fine) article describing how to perform color based object tracking in OpenCV. The general idea is simple - convert image to HSV color space, use inRange function to find pixels which might be your objects and then track them (most likely you will have to filter the pixels - find biggest contour or contour which shape is close to circle). Note that you will need to call inRange function 3 times (one for each ball).
Looking for a way for taking a screenshot of a particular area on the screen in C++. (So not the whole screen) Then it should save it as .png .jpg whatever to use it with another function afterwards.
Also, I am going to use it, somehow, with openCV. Thought i'd mention that, maybe it's a helpful detail.
OpenCV cannot take screenshots from your computer directly. You will need a different framework/method to do this. #Ben is correct, this link would be worth investigating.
Once you have read this image in, you will need to store it into a cv:Mat so that you are able to perform OpenCV operations on it.
In order to crop an image in OpenCV the following code snippet would help.
CVMat * imagesource;
// Transform it into the C++ cv::Mat format
cv::Mat image(imagesource);
// Setup a rectangle to define your region of interest
cv::Rect myROI(10, 10, 100, 100);
// Crop the full image to that image contained by the rectangle myROI
// Note that this doesn't copy the data
cv::Mat croppedImage = image(myROI);
I need to be able to detect the edges of a card, currently it works when the background is non-disruptive and best when it is contrasting but still works pretty well on a non-contrasting background.
The problem occurs when the card is on a disruptive background the bilateral filter lets in too much noise and causes inaccurate edge detection.
Here is the code I am using:
bilateralFilter(imgGray, detectedEdges, 0, 175, 3, 0);
Canny( detectedEdges, detectedEdges, 20, 65, 3 );
dilate(detectedEdges, detectedEdges, Mat::ones(3,3,CV_8UC1));
The imgGray being the grayscale version of the original image.
Here are some tests on a disruptive background and the results (contact info distorted in all images):
Colored card:
Result:
And here is a white card:
Results:
Can anyone tell me how I can preserve the edges of the card no matter the background, color while removing the noise?
Find the edges using canny which you are already doing, then find the contour in image and find the suitable rectangle using bounding box and apply some threshold on the occupancy and the dimensions of rectangle. This should zero down to your rectangle i.e. your card edges and take it as ROI on which you can further work.
I am currently working on image processing project. I am using Opencv2.3.1 with VC++.
I have written the code such that, the input image is filtered to only blue color and converted to a binary image. The binary image has some small objects which I don't want. I wanted to eliminate those small objects, so i used openCV's cvFindContours() method to detect contours in Binary image. but the problem is I cant eliminate the small objects in the image output. I used cvContourArea() function , but didn't work properly.. , erode function also didn't work properly.
So please someone help me with this problem..
The binary image which I obtained :
The result/output image which I want to obtain :
Ok, I believe your problem could be solved with the bounding box demo recently introduced by OpenCV.
As you have probably noticed, the object you are interested at should be inside the largest rectangle draw in the picture. Luckily, this code is not very complex and I'm sure you can figure it all out by investigating and experimenting with it.
Here is my solution to eliminate small contours.
The basic idea is check the length/area for each contour, then delete the smaller one from vector container.
normally you will get contours like this
Mat canny_output; //example from OpenCV Tutorial
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny(src_img, canny_output, thresh, thresh*2, 3);//with or without, explained later.
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
With Canny() pre-processing, you will get contour segments, however each segment is stored with boundary pixels as a closed ring. In this case, you can check the length and delete the small one like
for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
{
if (it->size()<contour_length_threshold)
it=contours.erase(it);
else
++it;
}
Without Canny() preprocessing, you will get contours of objects.
Similarity, you can also use area to define a threshold to eliminate small objects, as OpenCV tutorial shown
vector<Point> contour = contours[i];
double area0 = contourArea(contour);
this contourArea() is the number of non-zero pixels
Are you sure filtering by small contour area didn't work? It's always worked for me. Can we see your code?
Also, as sue-ling mentioned, it's a good idea to use both erode and dilate to approximately preserve area. To remove small noisy bits, use erode first, and to fill in holes, use dilate first.
And another aside, you may want to check out the new C++ versions of the cv* functions if you weren't aware of them already (documentation for findContours). They're much easier to use, in my opinion.
Judging by the before and after images, you need to determine the area of all the white areas or blobs, then apply a threshold area value. This would eliminate all areas less than the value and leave only the large white region which is seen in the 2nd image. After using the cvFindContours function, try using 0 order moments. This would return the area of the blobs in the image. This link might be helpful in implementing what I've just described.
http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/
I believe you can use morphological operators like erode and dilate (read more here)
You need to perform erosion with a kernel size near to the radius of the circle on the right (the one you want to eliminate).
followed by dilation using the same kernel to fill the gaps created by the erosion step.
FYI erosion followed by dilation using the same kernel is called opening.
the code will be something like this
int erosion_size = 30; // adjust with you application
Mat erode_element = getStructuringElement( MORPH_ELLIPSE,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
erode( binary_img, binary_img, erode_element );
dilate( binary_img, binary_img, erode_element );
It is not a fast way but may be usefull in some cases.
There is a new function in OpencCV 3.0 - connectedComponentsWithStats. With it we can get area of connected components and eliminate unnecessary. So we can easy remove circle with holes, with the same bounding box as solid circle.