漫画气球检测:如何计算OpenCV中矢量<rotatingrect> Ellipse内的白色像素?</rotaterect>

时间:2015-03-19 04:03:51

标签: c++ opencv image-processing feature-detection feature-extraction

我一直在寻找能找到答案但我无法找到的答案。

我正在制作一个漫画气球检测程序,我需要找到一个椭圆,在轮廓内部具有特定百分比的白色(百分比将在稍后决定),因此我需要计算轮廓内的白色像素我不知道怎么做。

我尝试了countNonZero(),但由于该参数是数组,因此不接受声明为minEllipse[i]的{​​{1}}或contours[i]

以下是代码:

vector<RotatedRect>

非常庞大的if语句让我获得漫画气球检测的准确率只有53%(更不用说所有的错误检测),这就是为什么我需要在轮廓中获得白色像素的百分比更高的百分比。

修改

我想要的输出是整个漫画页面除了漫画气球之外会是黑色的,然后计算那里的白色和黑色像素的数量

// Modified version of thresold_callback function // from http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.html Mat fittingEllipse(int, void*, Mat inputImage) { Mat threshold_output; vector<vector<Point> > contours; vector<Vec4i> hierarchy; int numberOfCaptions = 0; // Detect edges using Threshold threshold(inputImage, threshold_output, 224, 250, THRESH_BINARY); findContours(inputImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); vector<RotatedRect> minEllipse(contours.size()); Mat drawing = Mat::zeros(inputImage.size(), CV_8UC3); for (int i = 0; i < contours.size(); i++) { if (contours[i].size() > 5) minEllipse[i] = fitEllipse(Mat(contours[i])); } int totalContourSize = 0, whitepixels, blackpixels; //Draw ellipse/caption for (int i = 0; i < contours.size(); i++) { Scalar color = Scalar(255, 0, 0); if (minEllipse[i].size.height >= inputImage.rows / 8 && //IJIP-290-libre.pdf minEllipse[i].size.width >= inputImage.cols / 10 && //IJIP-290-libre.pdf minEllipse[i].size.height < inputImage.rows / 3 && minEllipse[i].size.width < inputImage.cols / 3 && ( (minEllipse[i].angle >= 0 && minEllipse[i].angle <= 10) || (minEllipse[i].angle >= 80 && minEllipse[i].angle <= 100) || (minEllipse[i].angle >= 170 && minEllipse[i].angle <= 190) || (minEllipse[i].angle >= 260 && minEllipse[i].angle <= 280) || (minEllipse[i].angle >= 350 && minEllipse[i].angle <= 360) )) { ellipse(drawing, minEllipse[i], color, -1, 8); } } drawing = binarizeImage(drawing); return drawing; } // end of fittingEllipse Mat CaptionDetection(Mat inputImage){ Mat outputImage, binaryImage, captionDetectImage; binaryImage = captionDetectImage = binarizeImage(inputImage); threshold(captionDetectImage, captionDetectImage, 224, 250, 0); //IJIP-290-libre.pdf GaussianBlur(captionDetectImage, captionDetectImage, Size(9, 9), 0, 0); captionDetectImage = fittingEllipse(0, 0, captionDetectImage); //binaryImage = invertImage(binaryImage); outputImage = inputImage; for (int i = 0; i < inputImage.rows; i++) { for (int j = 0; j < inputImage.cols; j++) { if (captionDetectImage.at<uchar>(i, j) == 0) { outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[2] = 0; } } } return outputImage; } // end of CaptionDetection 函数上的

ONLY 应该计算每个字幕的像素数

最终答案

我编辑了用户Kornel提供的代码

CaptionDetection

要编辑 Mat fittingEllipse(int, void*, Mat inputImage) { Mat outputImage; vector<Vec4i> hierarchy; int numberOfCaptions = 0; // Detect edges using Threshold threshold(inputImage, inputImage, 224, 250, THRESH_BINARY); findContours(inputImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); vector<RotatedRect> minEllipse(contours.size()); for (int i = 0; i < contours.size(); i++) { if (contours[i].size() > 5) minEllipse[i] = fitEllipse(Mat(contours[i])); } //Draw ellipse/caption outputImage = Mat::zeros(inputImage.size(), CV_8UC3); for (int i = 0; i < contours.size(); i++) { Scalar color = Scalar(255, 255, 255); Mat drawing = Mat::zeros(inputImage.size(), CV_8UC3); ellipse(drawing, minEllipse[i], color, -1, 8); drawing = binarizeImage(drawing); int area = countNonZero(drawing); if ((area >= 10000 && area <= 40000) && ( (minEllipse[i].angle >= 0 && minEllipse[i].angle <= 10) || (minEllipse[i].angle >= 80 && minEllipse[i].angle <= 100) || (minEllipse[i].angle >= 170 && minEllipse[i].angle <= 190) || (minEllipse[i].angle >= 260 && minEllipse[i].angle <= 280) || (minEllipse[i].angle >= 350 && minEllipse[i].angle <= 360) )){ ellipse(outputImage, minEllipse[i], color, -1, 8); captionMask[captionCount] = drawing; captionCount++; } } imwrite((string)SAVE_FILE_DEST + "out.jpg", outputImage); return outputImage; } // end of fittingEllipse Mat replaceROIWithOrigImage(Mat inputImg, Mat mask, int k){ Mat outputImage = inputImg; Mat maskImg = mask; imwrite((string)SAVE_FILE_DEST + "inputbefore[" + to_string(k) + "].jpg", inputImg); for (int i = 0; i < inputImg.rows; i++) { for (int j = 0; j < inputImg.cols; j++) { if (maskImg.at<uchar>(i, j) == 0) { inputImg.at<Vec3b>(i, j)[0] = inputImg.at<Vec3b>(i, j)[1] = inputImg.at<Vec3b>(i, j)[2] = 0; } } } imwrite((string)SAVE_FILE_DEST + "maskafter[" + to_string(k) + "].jpg", inputImg); return inputImg; } Mat CaptionDetection(Mat inputImage){ Mat outputImage, binaryImage, captionDetectImage; binaryImage = captionDetectImage = binarizeImage(inputImage); threshold(captionDetectImage, captionDetectImage, 224, 250, 0); //IJIP-290-libre.pdf GaussianBlur(captionDetectImage, captionDetectImage, Size(9, 9), 0, 0); captionDetectImage = fittingEllipse(0, 0, captionDetectImage); for (int i = 0; i < captionCount; i++){ Mat replacedImg = replaceROIWithOrigImage(inputImage.clone(), captionMask[i], i); int area = countNonZero(binarizeImage(replacedImg)); cout << area << endl; } return outputImage; } // end of CaptionDetection 中的if条件,以便以后获得更好的准确性。

感谢您的帮助和时间用户a-Jays和Kornel!

1 个答案:

答案 0 :(得分:0)

假设您有一个旋转的矩形rRect,它在代码中定义了一个椭圆,就像minEllipse[i]一样。

首先,它的面积可以通过闭合公式area = a * b * PI来估算,其中ab是半长轴和半短轴(1/2)椭圆的长轴和短轴),分别为:

cv::RotatedRect rRect(cv::Point2f(100.0f, 100.0f), cv::Size2f(100.0f, 50.0f), 30.0f);
float area = (rRect.size.width / 2.0f) * (rRect.size.height / 2.0f) * M_PI;

或者更短一些:

float area = (rRect.size.area() / 4.0f) * M_PI;

或者,您可以通过cv::ellipse()简单地在掩码上绘制它,即:

cv::Mat mask = cv::Mat::zeros(200, 200, CV_8UC1);
cv::ellipse(mask, rRect, cv::Scalar::all(255), -1);

你像往常一样计算非零元素:

int area = cv::countNonZero(mask);