霍夫环检测的确定性

时间:2020-06-10 13:52:29

标签: c++ opencv object-detection

最近我做了我的第一个视觉应用程序。 我的代码可以识别某种颜色的大理石,并为我提供该大理石的X,Y,Z坐标。 为了调试和设置系统,我编写了一些代码,可以轻松地对其进行调整和尝试设置。 这段代码尝试检测图像中的所有大理石,并通过用绿色点标记来告诉我大理石在哪里。

基本上我的代码是这样的: 我的相机拍照。

它会寻找一定范围内的颜色,并以此遮罩(范围内为白色,范围内为黑色),例如:image mask

然后我使用houghcircles命令在此图像中寻找圆圈。

我从每个检测到的圆中提取中心点,并将其放在原始图像上,如下所示:(绿色点=中心圆) output image

我的检测仍然存在一些问题,但目前我很满意。

现在,我想知道的是:是否可以在每个标记的中心点旁边放一个百分比,告诉我程序如何确定它是一个圆。

如果您有任何其他建议或问题,请随时提出。 我将代码放在下面:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <librealsense2/rs.hpp>


using namespace std;
using namespace cv;


Mat image;
Mat imgHSV;
Mat OutputImage;
Mat testframe;


int iLowH = 104;
int iHighH = 111;
int iLowS = 109;
int iHighS = 155;
int iLowV = 120;
int iHighV = 255;


int acc = 1;
int rows = 10;
int para1 = 100;
int para2 = 7;
int minRad = 3;
int maxRad = 14;


static void HSVthreshold(int, int, int, int, int, int, void*)
{
    inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), OutputImage);
}

static void Circle_detector(int, int, int, int, int, void*)
{
    vector<Vec3f> circles;
    HoughCircles(OutputImage, circles, HOUGH_GRADIENT, 1,
        OutputImage.rows / rows,      //change to detect circles that are closer to eachother
        para1, para2, minRad, maxRad);        //chang last to parameters to detect larger or smaller circles

    for (size_t i = 0; i < circles.size(); i++)
    {
        Vec3i c = circles[i];
        Point center = Point(c[0], c[1]);
        // circle center
        circle(testframe, center, 1, Scalar(0, 255, 0), 2, LINE_AA);
        // circle outline
        int radius = c[2];
        circle(imgHSV, center, radius, Scalar(255, 0, 0), 2, LINE_AA);
    }
}


int main()
{


    // Contructing piplines and other stuff to receive data from the realsense camera.

    //Contruct a pipeline which abstracts the device
    rs2::pipeline pipe;

    //Create a configuration for configuring the pipeline with a non default profile
    rs2::config cfg;

    //Add desired streams to configuration
    cfg.enable_stream(RS2_STREAM_COLOR, 640, 480, RS2_FORMAT_BGR8, 30);

    //Instruct pipeline to start streaming with the requested configuration
    pipe.start(cfg);

    // Camera warmup - dropping several first frames to let auto-exposure stabilize
    rs2::frameset frames;
    for (int i = 0; i < 30; i++)
    {
        //Wait for all configured streams to produce a frame
        frames = pipe.wait_for_frames();
    }
    while (waitKey(1) < 0)
    {
        frames = pipe.wait_for_frames();
        //Get each frame
        rs2::frame color_frame = frames.get_color_frame();






        // Creating OpenCV Matrix from a color image
        Mat color(Size(640, 480), CV_8UC3, (void*)color_frame.get_data(), Mat::AUTO_STEP);

        // Display in a GUI
        if (color.empty())
        {
            cerr << "image was not generated !" << endl;
            return 1;
        }

        testframe = color;

        namedWindow("Display Image", WINDOW_AUTOSIZE);
        imshow("Display Image", color);


        //convert RGB to HSV
        cvtColor(color, imgHSV, COLOR_BGR2HSV);


        //Create windows
        namedWindow("image", WINDOW_AUTOSIZE); //window for original image
        namedWindow("Control", WINDOW_AUTOSIZE); //window for HSV-control sliders
        namedWindow("Output", WINDOW_AUTOSIZE); //window for output mask
        namedWindow("Control HoughCircles", WINDOW_AUTOSIZE); //window for HoughCircle sliders

        namedWindow("Test-window", WINDOW_AUTOSIZE);

        //Create trackbars in "Control HSV" window
        createTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179)
        createTrackbar("HighH", "Control", &iHighH, 179);

        createTrackbar("LowS", "Control", &iLowS, 255); //Saturation (0 - 255)
        createTrackbar("HighS", "Control", &iHighS, 255);

        createTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255)
        createTrackbar("HighV", "Control", &iHighV, 255);

        int key = 0;
        while (key != 27) { // 27 is escape
            HSVthreshold(iLowH, iHighH, iLowS, iHighS, iLowV, iHighV, 0);
            imshow("Output", OutputImage);
            imshow("image", imgHSV);
            key = waitKey(1); // wait at most 1 ms for input, if nothing was pressed result is -1
        }


        //Optional filter --> does not work properly at the moment <--

        //morphological opening (remove small objects from the foreground)
        erode(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(1, 1)));
        dilate(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(1, 1)));


        //morphological closing (fill small holes in the foreground)
        dilate(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
        erode(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));


        imshow("Output", OutputImage);
        waitKey();


        //Create trackbars in "Control HoughCircles" window
        createTrackbar("Distance between detections", "Control HoughCircles", &rows, 50); //detection distance (0 - 50)


        createTrackbar("Upper threshold for internal canny edge", "Control HoughCircles", &para1, 100); //upper threshold for internal canny edge detector (0 - 100)
        createTrackbar("threshold for internal canny edge", "Control HoughCircles", &para2, 50); //threshold for internal canny edge detector (0 - 50)

        createTrackbar("Min radius", "Control HoughCircles", &minRad, 200); //minimum circle radius (0 - 200)
        createTrackbar("Max radiu", "Control HoughCircles", &maxRad, 200); // maximum circle radius (0 - 200)


        int key2 = 0;
        while (key2 != 27) { // 27 is escape
            Circle_detector(rows, para1, para2, minRad, maxRad, 0);
            imshow("image", imgHSV);
            imshow("Test-window", testframe);
            key2 = waitKey(1); // wait at most 1 ms for input, if nothing was pressed result is -1
        }

        waitKey();
    }
        return 0;
    }

编辑: 我为测试材料添加了一些新图片,可悲的是,由于光线条件,这并不完全等同于上述情况。

原始图片:Original image

黑白图像蒙版:Image mask

检测窗口:Detection window

1 个答案:

答案 0 :(得分:1)

我尝试了您添加的图片。与您的代码相比,我没有使用其他不同的东西。我专注于检查每个圆圈内的像素。这是我的步骤:

  • 将图像转换为HSV
  • 找到合适的大理石HSV值并将其应用
  • 使用medianBlur降低噪音
  • HoughCircles应用于二进制图像
  • 根据HoughCircles的输出,每个圆都被矩形裁剪
  • 检查裁切后的小图像的每个像素是否在圆内(我在此使用了半径和中心。如果每个像素到中心的长度大于半径,则该像素不在圆内,否则在圆内)
  • 最后,检查像素并计算所需的hsv值

这是我的代码和结果(结果与您的没什么不同,重要的部分是检查圆圈内):

代码:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <librealsense2/rs.hpp>

using namespace std;
using namespace cv;

int main()
{

    Mat color = imread("/ur/image/directory/marble.png",1);
    Mat hsv;
    cvtColor(color, hsv, COLOR_BGR2HSV);

    Mat board = Mat::zeros(hsv.rows,hsv.cols,CV_8UC1);

    for(int i=0; i<hsv.rows; i++)
    {
        for(int j=0; j<hsv.cols; j++)
        {
            if(hsv.at<Vec3b>(Point(j,i))[2]<60 && hsv.at<Vec3b>(Point(j,i))[2]>20 && hsv.at<Vec3b>(Point(j,i))[1]<120 && hsv.at<Vec3b>(Point(j,i))[1]>50
                    && hsv.at<Vec3b>(Point(j,i))[0]<105 && hsv.at<Vec3b>(Point(j,i))[0]>85)
                board.at<uchar>(Point(j,i)) = 254;
        }
    }

    medianBlur(board,board,3);            
    vector<Vec3f> circles;
    HoughCircles(board, circles, HOUGH_GRADIENT, 1,
                 board.rows / 10,      //change to detect circles that are closer to eachother
                 100, 7, 3, 14);        //chang last to parameters to detect larger or smaller circles

    for (size_t i = 0; i < circles.size(); i++)
    {
        Vec3i cc = circles[i];
        Point center = Point(cc[0], cc[1]);
        // circle center
        circle(color, center, 1, Scalar(0, 255, 0), 2, LINE_AA);
        // circle outline
        int radius = cc[2];
        circle(color, center, radius, Scalar(255, 0, 0), 2, LINE_AA);

        // Firstly, Crop that region
        Rect crop(center.x-radius-5, center.y-radius-5,2*radius+10,2*radius+10);
        Mat crop_for_test = hsv(crop);

        //Secondly, check each pixel inside the circle or not
        for(int r=0; r<crop_for_test.rows; r++)
        {
            for(int c=0; c<crop_for_test.cols; c++)
            {
                double length_to_center = norm(Point(cc[0]-(center.x-radius-5), cc[1]-(center.y-radius-5))-Point(r,c));

                if(length_to_center<radius)
                {
                    // Here all points inside the circle
                    cout<<"H value:  "<<to_string(crop_for_test.at<Vec3b>(Point(r,c))[2])<<"   "<<"S value:  "
                        <<to_string(crop_for_test.at<Vec3b>(Point(r,c))[1])<<"   "<<"V value:  "
                        <<to_string(crop_for_test.at<Vec3b>(Point(r,c))[0])<<endl;




                }
            }
        }
    }


    imshow("board",board);

    imshow("hsv",hsv);
    imshow("rgb",color);

    waitKey(0);

    return 0;
}

HSV输入:

enter image description here

过滤后的二进制文件:

enter image description here

输出:

enter image description here