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 изображение выглядит так Мне кажется, это нормально, но по какой-то причине прямоугольник не обнаружен. Может кто-нибудь объяснить, если что-то не так с моими параметрами?
Мой второй подход состоял в том, чтобы использовать обнаружение линий OpenCV Hough, в основном используя тот же код, что и выше, для изображения Canny, а затем я вызываю функцию HoughLines. Это дает мне довольно много линий, так как мне пришлось снизить порог, чтобы обнаружить вертикальные линии. Результирующие строки выглядят так:
Проблема в том, что есть много строк. Как я могу узнать линии, которые касаются сторон синего прямоугольника, как показано на первом изображении?
Или есть лучший подход для обнаружения экрана?
1 ответ
Прежде всего, найдите ссылку на максимальную площадь контура, затем определите минимальную ссылку на прямоугольник, разделите область контура на площадь прямоугольника, если она достаточно близка к 1, тогда ваш контур похож на прямоугольник. Это будет ваш требуемый контур и прямоугольник.