使用相机

时间:2017-11-08 08:51:49

标签: opencv hough-transform canny-operator straight-line-detection

我正在使用iPhone相机来检测电视屏幕。当前的方法是逐个像素地比较后续帧并跟踪累积差异。结果是二进制图像,如图像所示。Original image

对我来说,这看起来像一个矩形,但OpenCV并不这么认为。它的两侧不是完全笔直的,有时甚至会有更多的颜色流失,使检测变得困难。这是我的OpenCV代码试图检测矩形,因为我不熟悉OpenCV,它是从我发现的一些例子中复制的。

uint32_t *ptr = (uint32_t*)CVPixelBufferGetBaseAddress(buffer);
cv::Mat image((int)width, (int)height, CV_8UC4, ptr); // unsigned 8-bit values for 4 channels (ARGB)

cv::Mat image2 = [self matFromPixelBuffer:buffer];

std::vector<std::vector<cv::Point>>squares;

// blur will enhance edge detection

cv::Mat blurred(image2);
GaussianBlur(image2, blurred, cvSize(3,3), 0);//change from median blur to gaussian for more accuracy of square detection

cv::Mat gray0(blurred.size(), CV_8U), gray;

std::vector<std::vector<cv::Point> > contours;

// find squares in every color plane of the image
for (int c = 0; c < 3; c++) {
    int ch[] = {c, 0};
    mixChannels(&blurred, 1, &gray0, 1, ch, 1);

    // try several threshold levels
    const int threshold_level = 2;
    for (int l = 0; l < threshold_level; l++) {
        // Use Canny instead of zero threshold level!
        // Canny helps to catch squares with gradient shading
        if (l == 0) {
            Canny(gray0, gray, 10, 20, 3); //

            // Dilate helps to remove potential holes between edge segments
            dilate(gray, gray, cv::Mat(), cv::Point(-1,-1));
        } else {
            gray = gray0 >= (l+1) * 255 / threshold_level;
        }

        // Find contours and store them in a list
        findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

        // Test contours
        std::vector<cv::Point> approx;
        int biggestSize = 0;
        for (size_t i = 0; i < contours.size(); i++) {
            // approximate contour with accuracy proportional
            // to the contour perimeter
            approxPolyDP(cv::Mat(contours[i]), approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
            if (approx.size() != 4)
                continue;

            // Note: absolute value of an area is used because
            // area may be positive or negative - in accordance with the
            // contour orientation
            int areaSize = fabs(contourArea(cv::Mat(approx)));
            if (approx.size() == 4 && areaSize > biggestSize)
                biggestSize = areaSize;
            cv::RotatedRect boundingRect = cv::minAreaRect(approx);
            float aspectRatio = boundingRect.size.width /  boundingRect.size.height;

            cv::Rect boundingRect2 = cv::boundingRect(approx);
            float aspectRatio2 = (float)boundingRect2.width / (float)boundingRect2.height;

            bool convex = isContourConvex(cv::Mat(approx));
            if (approx.size() == 4 &&
                fabs(contourArea(cv::Mat(approx))) > minArea &&
                (aspectRatio >= minAspectRatio && aspectRatio <= maxAspectRatio) &&
                isContourConvex(cv::Mat(approx))) {
                double maxCosine = 0;

                for (int j = 2; j < 5; j++) {
                    double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                    maxCosine = MAXIMUM(maxCosine, cosine);
                }
                double area = fabs(contourArea(cv::Mat(approx)));
                if (maxCosine < 0.3) {
                    squares.push_back(approx);
                }
            }
        }
    }

Canny-step之后,图像看起来像这样 Image after Canny-step 对我来说似乎很好但是由于某种原因没有检测到矩形。谁能解释一下我的参数是否有问题?

我的第二种方法是使用OpenCV Hough线检测,基本上使用与上面相同的代码,对于Canny图像我然后调用HoughLines函数。它给了我很多行,因为我必须降低阈值以检测垂直线。结果是这样的:

Hough lines

问题是有很多行。如何找到触及蓝色矩形边的线条,如第一张图片所示?

或者有更好的方法来检测屏幕吗?

1 个答案:

答案 0 :(得分:1)

首先,找到最大区域轮廓reference,然后压缩最小区域矩形reference,按矩形区域划分轮廓区域,如果它足够接近1,那么您的轮廓类似于矩形。这将是您所需的轮廓和矩形。