I have found some code which recognize circles in particular image and I was able to convert 90% of that code it in to javacv. But unfortunately I couldn't able to convert following lines in to javacv. So please can some one help me to convert this lines into javacv ?
CvSeq circles = cvHoughCircles(gry, mem, CV_HOUGH_GRADIENT, 1, 40.0, 100, 100,0,0);
cvCvtColor(canny, rgbcanny, CV_GRAY2BGR);
for (int i = 0; i < circles->total; i++)
{
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
// draw the circle center
cvCircle(img, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(img, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}
I just need to know how to convert 5 code lines which inside the for loop. Please be kind enough to share your experience. Thanks.
Well, I'm not going to convert that code for you (I don't know JavaCV) but here's some useful links for you:
Hints for Converting OpenCV C/C++ code to JavaCV - this is the very first thing you should read.
JavaCV source code - in this archive there's file samples/HoughLines.java. It's very similar to HoughCircles.java wich was deleted from repo.
JavaCV examples - this archive contains file OpenCV2_Cookbook/src/opencv2_cookbook/chapter07/ex4HoughCircles.scala. And here's some part of code from this file:
// Draw lines on the canny contour image
val colorDst = cvCreateImage(cvGetSize(src), src.depth(), 3)
cvCvtColor(src, colorDst, CV_GRAY2BGR)
for (i <- 0 until circles.total) {
val point = new CvPoint3D32f(cvGetSeqElem(circles, i))
val center = cvPointFrom32f(new CvPoint2D32f(point.x, point.y))
val radius = math.round(point.z)
cvCircle(colorDst, center, radius, CV_RGB(255, 0, 0), 1, CV_AA, 0)
print(point)
}
show(colorDst, "Hough Circles")
This is exactly what you're looking for.
Related
I want to co-ordinates of lines with the help of OpenCV in android. I studied the tutorial and this is what my api call is
Mat ImageMat = new Mat(croppedImage.getHeight(), croppedImage.getWidth(), CvType.CV_8U, new Scalar(4));
int threshold = 50;
int minLineSize = 100;
int lineGap = 20;
Mat lines = new Mat();
Imgproc.HoughLinesP(ImageMat, lines, 1, Math.PI / 180, threshold, minLineSize, lineGap);
I provide a simple image with one line in it but in "lines" variable I get hundreds of co-ordinates. I just one co-ordinate of that single line. How to get co-ordinate of that single line only. Also what is the unit in which minLineSize is measured? My lines are the lines which are in front of FirstName, LastName etc.
Here's code in C++. Since mostly OpenCV functions are used, you might be able to port it do android CV easily:
int main()
{
// loading your image. you dont need theses parts
cv::Mat input = cv::imread("../inputData/FormularLineDetection.png");
// convert to grayscale: you will do something similar:
cv::Mat gray;
cv::cvtColor(input, gray, CV_BGR2GRAY);
// computation of binary thresholding so that dark areas of the image will bevcome "foreground pixel".
// If your image have bright features you'll have to choose different parameters.
// If you want to detect contour lines instead you'll compute gradient magnitude first.
cv::Mat mask;
cv::threshold(gray, mask, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
std::vector<cv::Vec4i> lines;
//cv::HoughLinesP(mask, lines, 1, CV_PI/180.0, 50, 50, 10 );
// I've changed the min-Size of a line to 1/3 of the images width. Maybe you'll have to adjust that parameter to your needs!
cv::HoughLinesP(mask, lines, 1, CV_PI/180.0, 50, input.cols/3, 10 );
// draw the lines to visualize: you might not do this at all
for( size_t i = 0; i < lines.size(); i++ )
{
cv::Vec4i l = lines[i];
cv::line( input, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0,0,255), 3, CV_AA);
}
// display and save to disk
cv::imshow("mask", mask); // you might not want to display the image here.
cv::imshow("output",input);
cv::imwrite("../outputData/FormularLineDetection.png", input);
cv::waitKey(0);
return 0;
}
with your input I get this output:
as you can see, your desired lines are detected, but in addition that big thick "line" is detected too. You might want to try to detect structures like that and filter them out!
This code is OpenCV c++:
lines = cvHoughCircles(frame2, storage, CV_HOUGH_GRADIENT, 1, 50, 300, 60, 10, 600);
for (int i = 0; i < lines.total(); i++) {
//Would like the code to go here
CvPoint2D32f point = new CvPoint2D32f(cvGetSeqElem(lines, i));
cvCircle(src, cvPoint((int)point.x(), (int)point.y()), 3, CvScalar.WHITE, -1, 8, 0);
Point p = new Point((int)point.x(), (int)point.y());
points.add(p);
}
What is the correspondent in the new Java Api? I cannot get CvPoint2D32f, cvGetSeqElem and CV_AA. I found that existed in JavaCV but cannot find them in OpenCV Java api.
Thanks
EDIT:
I've changed my code and now I have:
MatOfPoint3 circles = new MatOfPoint3();
Imgproc.HoughCircles(image, circles, Imgproc.CV_HOUGH_GRADIENT,2, image.rows()/4,200,100,0,0);
for(Point3 circle : circles.toArray()){
Point center = new Point(circle.x, circle.y);
int radius = (int) Math.round(circle.z);
Core.circle(image, center, radius, new Scalar(0,255,0), 6, 8, 0);
}
However I got an error at for(Point3 circle : circles.toArray()):
Exception in thread "main" java.lang.UnsupportedOperationException: Mat data type is not compatible: 21
at org.opencv.core.Mat.get(Mat.java:2581)
at org.opencv.core.MatOfPoint3.toArray(MatOfPoint3.java:64)
at org.opencv.core.MatOfPoint3.toList(MatOfPoint3.java:76)
at main.java.DetectFaceDemo.run(HelloOpenCV.java:60)
at main.java.HelloOpenCV.main(HelloOpenCV.java:83)
Any thoughts on this? Thanks
EDIT 2:
The solution to last edit problem resides in
MatOfPoint3 circles = new MatOfPoint3();
It must be
MatOfPoint3f circles = new MatOfPoint3f();
Use Class Point3. Template class for 3D points specified by its coordinates x, y and z. An instance of the class is interchangeable with the C structure CvPoint2D32f. Similarly to Point_, the coordinates of 3D points can be converted to another type. The vector arithmetic and comparison operations are also supported.
Currently I am developing image processing project and I'm using javacv to develop image processing components. I was able to extract some interesting parts of a image and now I need to read the x and y coordinates of those objects.
This is the image that I haveextracted
And I need to identify those objects and draw square around those objects. I went through some tutorials and try to identify objects using following code.
IplImage img="sourceimage";
CvSize sz = cvSize(img.width(), img.height());
IplImage gry=cvCreateImage(sz, img.depth(), 1);
cvCvtColor(img, gry, CV_BGR2GRAY);
cvThreshold(gry, gry, 200, 250, CV_THRESH_BINARY);
CvMemStorage mem = CvMemStorage.create();
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
cvFindContours(gry, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
CvRect boundbox;
for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
boundbox = cvBoundingRect(ptr, 0);
if(boundbox.height()>10||boundbox.height()>10){
cvRectangle( gry, cvPoint( boundbox.x(), boundbox.y() ), cvPoint( boundbox.x() + boundbox.width(), boundbox.y() + boundbox.height()),CvScalar.BLUE, 0, 0, 0 );
System.out.println(boundbox.x()+", "+boundbox.y());
}
}
cvShowImage("contures", gry);
cvWaitKey(0);
But it doesn't draw as rectangle around the objects. I would like to know whether I can use cvFindContours method to identify those objects ? Please can some one explain how to archive my objective using javacv/opencv?
Try to go through following code and it will give answer for your question.
IplImage img=cvLoadImage("pathtosourceimage");
CvSize cvSize = cvSize(img.width(), img.height());
IplImage gry=cvCreateImage(cvSize, img.depth(), 1);
cvCvtColor(img, gry, CV_BGR2GRAY);
cvThreshold(gry, gry, 200, 255, CV_THRESH_BINARY);
cvAdaptiveThreshold(gry, gry, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, 11, 5);
CvMemStorage storage = CvMemStorage.create();
CvSeq contours = new CvContour(null);
int noOfContors = cvFindContours(gry, storage, contours, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, new CvPoint(0,0));
CvSeq ptr = new CvSeq();
int count =1;
CvPoint p1 = new CvPoint(0,0),p2 = new CvPoint(0,0);
for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
CvScalar color = CvScalar.BLUE;
CvRect sq = cvBoundingRect(ptr, 0);
System.out.println("Contour No ="+count);
System.out.println("X ="+ sq.x()+" Y="+ sq.y());
System.out.println("Height ="+sq.height()+" Width ="+sq.width());
System.out.println("");
p1.x(sq.x());
p2.x(sq.x()+sq.width());
p1.y(sq.y());
p2.y(sq.y()+sq.height());
cvRectangle(img, p1,p2, CV_RGB(255, 0, 0), 2, 8, 0);
cvDrawContours(img, ptr, color, CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0,0));
count++;
}
cvShowImage("contures",img);
cvWaitKey(0);
This is the output that I got for your given image.
Did you know that findContours function finds white contours on black background?
Just do bitwise_not (or analogue in JavaCV) to your image and after this apply findContours. This is actually fix to your problem.
No need for third party libraries! What you are looking for can be achieved in OpenCV using a technique known as bounding box:
The trick is to use cvFindContours() to retrieve the contours and then cvApproxPoly() to improve the result. Notice that you'll have to invert the colors of the input image using cvNot() because cvFindContours() search for white contours.
There's a nice introduction to contours in this post.
There's a Java demo that implements a version of the bounding box to detect car number plates.
By the way cvMinEnclosingCircle() returns the center of the circle as CvPoint2D32f.
cvFindContours is the right solution to your problem.
And I have verified that it works on your images.
You have System.out.println inside, what's the output?
cvFindContours could be tricky to use, I have wrapped it into a more general C++ function. Also I use a class called vBlob to describe an object cvFindContours detects. From what I see from your java code, java version API is very similar to C/C++ version. So it won't be hard to rewrite it.
ps. Astor gave the right answer.
I m using c++ api but I think there should also be some function in javacv named drawContours or cvDrawContours which uses the output of findContours.
I've looked at JavaCV wrapper for OpenCV library and I saw that it is possible to use that library in Java for face detection on an image, but I was wondering is it possible to use that library for detecting traffic warning signs on an image and how?
I have pictures taken from the road that look like this: http://www.4shared.com/photo/5QxoVDwd/041.html
and the result of detection should look sometning like this or similar: http://www.4shared.com/photo/z_pL0lSK/overlay-0.html
EDIT:
After I detect red color I get this image:
And I have a problem detecting just the warning sign triangle shape and ignore all other shapes. I tried changing the cvApproxPoly parameters but with no result. This is my code:
public void myFindContour(IplImage image)
{
IplImage grayImage = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvCvtColor(image, grayImage, CV_BGR2GRAY);
CvMemStorage mem;
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
cvThreshold(grayImage, grayImage, 150, 255, CV_THRESH_BINARY);
mem = cvCreateMemStorage(0);
cvFindContours(grayImage, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
Random rand = new Random();
while (contours != null && !contours.isNull()) {
if (contours.elem_size() > 0) {
CvSeq points = cvApproxPoly(contours, Loader.sizeof(CvContour.class),
mem, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0);
Color randomColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat());
CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue());
cvDrawContours(image, points, color, CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0,0));
}
contours = contours.h_next();
}
cvSaveImage("myfindcontour.png", image);
}
This is the output that i get (I used different colors for every shape, but in the final output i will use only white for detected warning sign and everything other left black):
You have to do the following:
Detect red color on image - you will get 1bit image where: 0=non-red, 1=red.
Detect triangles on created in previous step image. You can do that using approxPoly function.
see ,the first find the contour area.
compare it with the precalculated value and keep it with in a range
like
if(area>Mincontourarea && area<maxcontourare)
{
thats it now we have the signboard do
}
the value if calculated wouldnot be bigger than the car conotur,
to get the contoutr
up to my knowledge u need
Moments operator
code for the momnts operator:
Moments moment = moments((cv::Mat)contours[index]);
area = moment.m00; //m00 gives the area of the detected contour
put the above code before the if block discussed above
if you want the x and y coordinates put a post again..
take a look of my answer, it is in c++ but using opencv it is able to detect road signs, you can take it as a good example.
https://stackoverflow.com/a/52651521/8035924
I'm trying to detect the center of a circle. I try to do this with cvHoughCircle. But I can't seem to get it working properly .
The only thing that can vary is the size of the circle.
I try detecting the circle by doing :
circle = cvHoughCircles(imgThreshold, storage, CV_HOUGH_GRADIENT, 1,
(double)imgThreshold.height()/20, 200, 20, 0, 0);
imgThreshold is the b/w image you can see here. The resolution of the image is in fact 1280*1024.
Can anyone tell me what I am doing wrong.
Instead of using cvHoughCircle it is possible to solve this problem with a bit of math:
CvMoments moments = new CvMoments();
cvMoments(imgThreshold, moments, 1);
double moment10 = cvGetSpatialMoment(moments, 1, 0);
double moment01 = cvGetSpatialMoment(moments,0,1);
double area = cvGetCentralMoment(moments, 0, 0);
int posX = 0;
int posY = 0;
int lastX = posX;
int lastY = posY;
posX = (int) (moment10/area);
posY = (int) (moment01/area);
cvCircle(iplRgbImage, new CvPoint(posX,posY), 3, CvScalar.GREEN, -1, 8, 0);
source = http://aishack.in/tutorials/tracking-colored-objects-in-opencv/
If the circle is complete and filled and not occluded by other shapes, you can use findContours() and then find the center of the contour.
use cvBlob
https://code.google.com/p/cvblob/
Concerning Hough transform it can detect circles by identifying pixels that belongs to a circle periphery. More precisely given a binary (thresholded) image containing ie white pixels along a cyclic path, the hough circle transform will detect the circle. So the image to feed the algorithm should be binary and thresholded but in your example must be the thresholded example of an edge filter (ex Sobel) rather than a solid filled circle.
I can not tell a right way of "fitting" a circle on the above image, but the centroid of the blob extracted with connected components is a good and fast way to go.