float mvContours::match_circle (IplImage* img, MvCircleVector* circle_vector, COLOR_TRIPLE color, int method) { assert (img != NULL); assert (img->nChannels == 1); int n_contours = find_contour_and_check_errors(img); if (n_contours < 1 || m_contours == NULL) return -1; bin_calc.start(); CvSeq* c_contour = m_contours; int n_circles = 0; // debug //mvWindow window("contours"); // examine each contour, put the passing ones into the circle_vector for (int C = 0; C < n_contours; C++, c_contour = c_contour->h_next) { // debug /*cvZero (img); draw_contours (c_contour, img); //window.showImage (img); cvWaitKey(0);*/ // check that there are at least 6 points if (c_contour->total < 6) { continue; } // check the contour's area to make sure it isnt too small double area = cvContourArea(c_contour); if (area < img->width*img->height/600) { DEBUG_PRINT ("Circle Fail: Contour too small!\n"); continue; } // do some kind of matching to ensure the contour is a circle CvMoments moments; cvContourMoments (c_contour, &moments); cv::Moments cvmoments(moments); double nu11 = cvmoments.nu11; double nu20 = cvmoments.nu02; double nu02 = cvmoments.nu20; double nu21 = cvmoments.nu21; double nu12 = cvmoments.nu12; double nu03 = cvmoments.nu03; double nu30 = cvmoments.nu30; double r03 = fabs(nu30 / nu03); r03 = (r03 > 1) ? r03 : 1.0/r03; double r12 = fabs(nu12 / nu21); r12 = (r12 > 1) ? r12 : 1.0/r12; double r02 = fabs(nu02 / nu20); r02 = (r02 > 1) ? r02 : 1.0/r02; double r11 = fabs( MEAN2(nu02,nu20) / nu11); double R = MEAN2(nu20,nu02) / std::max((MEAN2(nu21,nu12)), (MEAN2(nu30,nu03))); bool pass = true; pass = (r03 <= 25.0) && (r12 <= 12.0) && (r02 <= 12.0) && (r11 > 2.5) && (R > 25); if (!pass) { //DEBUG_PRINT ("Circle Moms: nu11=%lf, nu20=%lf, nu02=%lf, nu21=%lf, nu12=%lf, nu30=%lf, nu03=%lf\n", nu11, nu20, nu02, nu21, nu12, nu30, nu03); DEBUG_PRINT ("Circle Fail: \tn30/n03=%3.1lf, n21/n12=%3.1lf, nu20/nu02=%3.1lf, r11=%3.1f, R=%3.1f!\n", r03, r12, r02, r11, R); continue; } // get area and perimeter of the contour //double perimeter = cvArcLength (c_contour, CV_WHOLE_SEQ, 1); // get min enclosing circle and radius CvPoint2D32f centroid32f; float radius; cvMinEnclosingCircle(c_contour, ¢roid32f, &radius); if (radius > img->width/2 || radius < 0) { continue; } // do checks on area and perimeter double area_ratio = area / (CV_PI*radius*radius); //double perimeter_ratio = perimeter / (2*CV_PI*radius); if (area_ratio < 0.7) { DEBUG_PRINT ("Circle Fail: Area: %6.2lf\n", area_ratio); continue; } MvCircle circle; circle.center.x = static_cast<int>(centroid32f.x); circle.center.y = static_cast<int>(centroid32f.y); circle.radius = radius; circle.m1 = color.m1; circle.m2 = color.m2; circle.m3 = color.m3; assign_color_to_shape (color, &circle); circle.validity = area_ratio; circle_vector->push_back(circle); //cvCircle (img, cvPoint(x,y), static_cast<int>(radius), CV_RGB(50,50,50), 2); n_circles++; } bin_calc.stop(); return n_circles; }
bool ShapeFilter::findCirc(cv::Mat img){ //getting the contours cv::Mat canny; std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; float radius; cv::Point2f center; this->radius.clear(); this->center.clear(); int thresh = 100; // Detect edges using canny Canny(img, canny, thresh, thresh*2, 3 ); // Find contours findContours( canny, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); int circlesFound = 0; //constants unsigned int minPoints = 6; double minArea = 10; float minRad = 100; for (std::vector<cv::Point> co: contours){ if (co.size() < minPoints){ println("Circle Not enough Points"); continue; } double area = cv::contourArea(co); if (area < minArea) { println ("Circle not enough area " + std::to_string(area)); continue; } /* /// Get the moments std::vector<cv::Moments> mu(co.size() ); for( int i = 0; i < co.size(); i++ ){ mu[i] = moments( co[i], false ); } /// Get the mass centers: std::vector<cv::Point2f> mc( contours.size() ); for( int i = 0; i < contours.size(); i++ ) { mc[i] = cv::Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); } */ cv::Moments cvmoments = moments(co, false); double nu11 = cvmoments.nu11; double nu20 = cvmoments.nu02; double nu02 = cvmoments.nu20; double nu21 = cvmoments.nu21; double nu12 = cvmoments.nu12; double nu03 = cvmoments.nu03; double nu30 = cvmoments.nu30; double r03 = fabs(nu30 / nu03); r03 = (r03 > 1) ? r03 : 1.0/r03; double r12 = fabs(nu12 / nu21); r12 = (r12 > 1) ? r12 : 1.0/r12; double r02 = fabs(nu02 / nu20); r02 = (r02 > 1) ? r02 : 1.0/r02; double r11 = fabs( MEAN2(nu02,nu20) / nu11); double R = MEAN2(nu20,nu02) / std::max((MEAN2(nu21,nu12)), (MEAN2(nu30,nu03))); bool pass = true; pass = (r03 <= 25.0) && (r12 <= 12.0) && (r02 <= 12.0) && (r11 > 2.5) && (R > 25); if (!pass){ println("Circle failed math test"); continue; } // get min enclosing circle and radius //CvPoint2D32f centroid32f; //cv::minEnclosingCircle(co, ¢roid32f, &radius); cv::minEnclosingCircle(co, center, radius); if (radius > minRad || radius < 0) { println("Circle radius too small"); continue; } // do checks on area and perimeter double area_ratio = area / (CV_PI*radius*radius); //double perimeter_ratio = perimeter / (2*CV_PI*radius); if (area_ratio < 0.7) { println("Circle fail Area"); continue; } bool repeat = false; //check if circle is found already for (unsigned int i = 0; i < this->center.size(); i++){ cv::Point2f c = this->center[i]; if (std::abs(c.x-center.x) < 20 && std::abs(c.y - center.y) < 20){ repeat = true; break; } } if (!repeat){ //check if i found the number of circles requested if (this->center.size() < max){ println("Found circle"); this->radius.push_back(radius); this->center.push_back(center); circlesFound++; }else{ println("Already found enough circles"); } }else{ println("Already found this circle"); } } return circlesFound != 0; }