[英]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
,其中a
和b
是半长轴和半短轴(椭圆的长轴和短轴的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.