OpenCV обнаружение экрана с помощью камеры

Я использую камеру iPhone, чтобы обнаружить экран телевизора. Текущий подход состоит в том, чтобы сравнивать последующие кадры попиксельно и отслеживать совокупные различия. Результатом является двоичное изображение, как показано на рисунке. Исходное изображение

Для меня это выглядит как прямоугольник, но 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 изображение выглядит так Изображение после Canny-step Мне кажется, это нормально, но по какой-то причине прямоугольник не обнаружен. Может кто-нибудь объяснить, если что-то не так с моими параметрами?

Мой второй подход состоял в том, чтобы использовать обнаружение линий OpenCV Hough, в основном используя тот же код, что и выше, для изображения Canny, а затем я вызываю функцию HoughLines. Это дает мне довольно много линий, так как мне пришлось снизить порог, чтобы обнаружить вертикальные линии. Результирующие строки выглядят так:

Линии Хаф

Проблема в том, что есть много строк. Как я могу узнать линии, которые касаются сторон синего прямоугольника, как показано на первом изображении?

Или есть лучший подход для обнаружения экрана?

1 ответ

Прежде всего, найдите ссылку на максимальную площадь контура, затем определите минимальную ссылку на прямоугольник, разделите область контура на площадь прямоугольника, если она достаточно близка к 1, тогда ваш контур похож на прямоугольник. Это будет ваш требуемый контур и прямоугольник.

Другие вопросы по тегам