CV 霍夫圆参数检测圆

Posted

技术标签:

【中文标题】CV 霍夫圆参数检测圆【英文标题】:CV Hough Circle Parameters to detect Circles 【发布时间】:2011-10-12 01:38:29 【问题描述】:

我正在尝试检测斯诺克台球桌上的 22 个球。我有一个图像要测试,但程序 os 检测到 2 个球和其他地方的随机圆圈。我的代码在下面带有圆形检测算法。有谁知道应该调整哪些参数以获得我需要的检测?谢谢

#include <cv.h>
#include <highgui.h>
#include <math.h>

int main(int argc, char** argv)
   int edge_thresh = 1;
    IplImage* img = cvLoadImage("C:\\Users\\Nathan\\Desktop\\SnookerPic.png", 1);;
    IplImage* gray = cvCreateImage(cvGetSize(img), 8, 1);
     IplImage *edge = cvCreateImage( cvSize(img->width,img->height), 8, 1);
    CvMemStorage* storage = cvCreateMemStorage(0);
    cvCvtColor(img, gray, CV_BGR2GRAY);
    cvThreshold(gray,gray, CV_GAUSSIAN, 9, 9);
    cvSmooth(gray, gray, CV_GAUSSIAN, 11, 11); 
    cvCanny(gray, edge, (float)edge_thresh, (float)edge_thresh*3, 5);
    CvSeq* circles = cvHoughCircles(edge, storage, 
        CV_HOUGH_GRADIENT, 2, 20, 200, 50);
    int i;

    for (i = 0; i < circles->total; i++) 
    
         float* p = (float*)cvGetSeqElem( circles, i );
         cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 
             3, CV_RGB(0,255,0), -1, 8, 0 );
         cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 
             cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0 );
    
    cvNamedWindow( "circles", 1 );
    cvShowImage( "circles", img );


    return 0;

【问题讨论】:

如果您分享您在测试中使用的图像,这将对您有很大帮助。 【参考方案1】:

我怀疑您在参数过于严格或过于宽松时遇到了问题。您需要使用参数,直到获得所需的圈数。此外,高斯 11x11 模糊可能有点激进,具体取决于图像。对我的形象来说,弊大于利,但我的形象有点理想化了……

我修改了您正在使用的 OpenCV 示例,以包含允许您使用 Canny 参数的轨迹栏。这应该真的可以帮助您了解它是如何工作的。另外,请注意 minDist 参数。对于我的图像,圆心距离大约 32 像素。您需要将其调整为您的圈子大小。所以,这里是示例:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

int hi = 1, lo = 1;

int main(int argc, char* argv[]) 
    Mat orig = imread("Snooker_balls_triangled.png");
    int key = 0;

    namedWindow("circles", 1);
    createTrackbar("hi", "circles", &hi, 255);
    createTrackbar("lo", "circles", &lo, 255);

    do
    
        // update display and snooker, so we can play with them
        Mat display = orig.clone();

        Mat snooker;
        cvtColor(orig, snooker, CV_RGB2GRAY);

        vector<Vec3f> circles;

        // also preventing crash with hi, lo threshold here...
        HoughCircles(snooker, circles, CV_HOUGH_GRADIENT, 2, 32.0, hi > 0 ? hi : 1, lo > 0 ? lo : 1 );
        for( size_t i = 0; i < circles.size(); i++ )
        
             Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
             int radius = cvRound(circles[i][2]);

             // draw the green circle center
             circle( display, center, 3, Scalar(0,255,0), -1, 8, 0 );

             // draw the blue circle outline
             circle( display, center, radius, Scalar(255,0,0), 3, 8, 0 );
        

        imshow( "circles", display );
        imshow("snooker", snooker);
        key = waitKey(33);
     while((char)key != 27);
    return 0;

我使用了这个snooker image,this 是我得到的输出。

(PS 考虑使用 C++ 接口,它远优于 C 接口恕我直言:)

【讨论】:

感谢一百万。你的很多代码与我的不同,我真的不明白轨迹栏的目的是什么。所有的 CvCanny 都在哪里。 cvThreshold 等去吗? 我正在使用 OpenCV 2.3.1 的 C++ 接口(尽管我认为没有任何功能比 OpenCV 2.2 更新,所以应该也可以)。轨迹栏只允许您调整 Canny 阈值以查看它对图像所做的更改。作为练习,您可以为 minDist 参数添加另一个轨迹栏。最后,HoughCircles 实际上已经对图像执行了 Canny 操作以找到圆圈。这就是 hi 和 lo 变量的用途。【参考方案2】:

如果您使用的是 ios,则需要包含 ios.h,或者只需编写自己的类方法来处理从 cvMat 到 UIImage 的 img proc,反之亦然。

请原谅 cmets,我仅将它们包含在那些可能发现了与我相同的“胡言乱语”研究的人中。每个图像都需要完全不同的设置。不放弃。 houghcircles 是目前最好的检测算法。 我将把一些游戏代码与检测结合起来,让它变得更好、更简单、更快。

    #import "JmBViewController.h"

@interface JmBViewController ()

@end

@implementation JmBViewController

- (void)viewDidLoad 
[super viewDidLoad];
_imgtest = [UIImage imageNamed:@"IMG_0424.PNG"];

cv::Mat cvImage;
UIImageToMat(_imgtest, cvImage);
if (!cvImage.empty()) 
    cv::Mat gray;
  //  cv::Mat filteredMat;
    cv::cvtColor(cvImage, gray, CV_BGRA2GRAY);
   // cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.2, 1.2);
    cv::vector<cv::Vec3f> circles;
    //cv::HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 1, 50);
    /*
    for(size_t i = 0; i < circles.size(); i++)
    
        cv::Point center((cvRound(circles[i][0]), cvRound(circles[i][1])));
        int radius = cvRound(circles[i][2]);
        cv::circle(gray, center, 3, cv::Scalar(0,255,0));
        cv::circle(gray, center, radius, cv::Scalar(0,0,255));
    
   */

 //  for ( int i = 1; i < 15; i = i + 2 )

        cv::GaussianBlur(gray, gray, cv::Size(9, 9), 1.5, 1.5);

        cv::Mat edges;
        cv::Canny(gray, edges, 0, 50);
        //gray.setTo(cv::Scalar::all(0));
        //gray.setTo(cv::Scalar::all(255), edges);
        cv::HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 1, gray.rows/30, 100, 50, 10, 30 );
        for(size_t i = 0; i < circles.size(); i++)
        
            cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
            int radius = cvRound(circles[i][2]);
            cv::circle(cvImage, center, 5, cv::Scalar::all(200), -1, 8, 0 );//center
            cv::circle(cvImage, center, radius, cv::Scalar::all(255), 3, 8, 0 );//diamter
        NSLog(@"Circles: %ld", i+1);

       // cv::imshow(&"circles i " [ i], gray);
    


    _imgView.image = MatToUIImage(cvImage);
    
    /*
cv::Mat cvImage;
cv::Mat grey;
cv::Mat filteredMat;
cv::vector<cv::Vec3f> circles;
// cv::cvtColor(_imgtest, cvImage, CV_BGR2GRAY);
cv::threshold(grey, filteredMat, 100, 255, CV_THRESH_BINARY);
[UIImageCVMatConverter cvMatGrayFromUIImage:_imgtest];
//  cv::cvtColor(cvImage, grey, CV_RGBA2GRAY);
// UIImageToMat(_imgtest, cvImage);
cv::HoughCircles(cvImage, circles, CV_HOUGH_GRADIENT, 1, 50);
//  MatToUIImage(cvImage);
_imgView.image = [UIImageCVMatConverter UIImageFromCVMat:cvImage];
_imgView.image = MatToUIImage(cvImage);
*/

// Do any additional setup after loading the view, typically from a nib.


- (void)didReceiveMemoryWarning

[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.

/*

UIImage* MatToUIImage(const cv::Mat& image) 
NSData *data = [NSData dataWithBytes:image.data length:image.elemSize()*image.total()];
CGColorSpaceRef colorSpace;
if (image.elemSize() == 1) 
    colorSpace = CGColorSpaceCreateDeviceGray();
else  colorSpace = CGColorSpaceCreateDeviceRGB();
 
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

CGImageRef imageRef = CGImageCreate(image.cols, image.rows, 8, 8*image.elemSize(), image.step.p[0], colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault, provider, NULL, FALSE, kCGRenderingIntentDefault);
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];

return finalImage;
 
 */


@end

【讨论】:

以上是关于CV 霍夫圆参数检测圆的主要内容,如果未能解决你的问题,请参考以下文章

python - OpenCV 霍夫圆变换检测球体

OpenCV---圆检测

opencv python:直线检测 与 圆检测

如何在 cv2 和 python 中使用霍夫圆?

使用霍夫变换检测圆

Python,OpenCV中的霍夫圆变换——cv2.HoughCircles()