简体   繁体   English

漫画气球检测:如何计算向量中的白色像素 <RotatedRect> OpenCV中的椭圆形?

[英]Comic Balloon Detection: How can I count white pixels inside a vector<RotatedRect> Ellipse in OpenCV?

I've been looking everywhere I can for the answer but I can't find one. 我一直在到处寻找答案,但找不到。

I'm making a comic balloon detection program and I need to find an ellipse that have a specific percentage of white inside the contour (percentage is to be decided later), thus why I need to count the white pixels inside the contour and I don't know how. 我正在制作一个漫画气球检测程序,我需要找到一个在轮廓内具有特定百分比的白色的椭圆(百分比待定),因此为什么我需要计算轮廓内的白色像素而我却不不知道如何

I have tried countNonZero() but since the parameter of that is an array it doesn't accept my minEllipse[i] or contours[i] that are declared as vector<RotatedRect> . 我已经尝试过countNonZero()但是由于该参数是一个数组,因此它不接受声明为vector<RotatedRect> minEllipse[i]contours[i]

Below is the code: 下面是代码:

// 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

The very bulky if statement yields me only 53% accuracy of getting the comic balloon detection (not to mention all the false detections), that's why I need to get the percentage of white pixels in the contours that are found to get a higher percentage. 非常笨重的if语句仅使我获得漫画气球检测的准确率达到53%(更不用说所有错误检测了),这就是为什么我需要获得轮廓中白色像素所占百分比的原因,发现白色像素所占的百分比更高。

EDIT: 编辑:

My desired output would be the whole manga page would be black except the comic balloons and then count the number of white and black pixels there 我想要的输出将是整个漫画页面将是黑色的,除了漫画气球,然后计算那里的白色和黑色像素的数量

ONLY on the CaptionDetection function should I count the number of pixels for each captions 我只应在CaptionDetection函数上计算每个字幕的像素数

FINAL ANSWER 最终答案

I edited the code that user Kornel gave 我编辑了用户Kornel提供的代码

            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

The if condition in fittingEllipse() is to be edited for better accuracy later. 稍后将编辑fittingEllipse()的if条件,以提高准确性。

Thank you for your help and time user a-Jays and Kornel! 感谢您对a-Jays和Kornel的帮助和时间用户!

Say you have a rotated rectangle rRect which defines an ellipse just like minEllipse[i] in your code. 假设您有一个旋转矩形rRect ,它定义了一个椭圆,就像代码中的minEllipse[i]一样。

First of all, the area of it can be estimated by the closed formula area = a * b * PI , where a and b are the semi-major and semi-minor axes (1⁄2 of the ellipse's major and minor axes), respectively, so: 首先,可以通过闭合公式area = a * b * PI来估计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;

Or a bit shorter: 或更短:

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

Alternatively, you can simply draw it over a mask by cv::ellipse() , ie: 或者,您可以通过cv::ellipse()将其简单地绘制在蒙版上,即:

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

And you count the non-zero elements as the usual: 您通常会计算非零元素:

int area = cv::countNonZero(mask);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM