Esempio n. 1
0
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, &centroid32f, &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;
}
Esempio n. 2
0
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, &centroid32f, &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;
}