【发布时间】:2015-05-22 02:53:50
【问题描述】:
我一直在寻找答案,但我找不到答案。
我正在制作一个漫画气球检测程序,我需要找到一个在轮廓内具有特定百分比白色的椭圆(百分比稍后确定),因此我需要计算轮廓内的白色像素我不知道怎么做。
我已经尝试过countNonZero(),但由于它的参数是一个数组,它不接受我声明为vector<RotatedRect> 的minEllipse[i] 或contours[i]。
下面是代码:
// 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
非常庞大的 if 语句让我获得漫画气球检测的准确率只有 53%(更不用说所有的错误检测了),这就是为什么我需要获取轮廓中白色像素的百分比以得到更高的百分比。
编辑:
我想要的输出是整个漫画页面除了漫画气球之外都是黑色的,然后计算那里的白色和黑色像素的数量
仅在 CaptionDetection 函数上我应该计算每个字幕的像素数
最终答案
我编辑了用户 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
fittingEllipse() 中的 if 条件将在以后进行编辑以提高准确性。
感谢您的帮助和时间用户 a-Jays 和 Kornel!
【问题讨论】:
-
一旦你有了一个轮廓,找到你的非零像素inside那个轮廓。
-
@a-Jays 抱歉,这是我的问题,我不知道如何在轮廓内找到它。
-
在图像上使用轮廓形状的蒙版,然后在新蒙版图像中找到非零像素。 stackoverflow.com/questions/8145036/…
-
@a-Jays 但这样做我只会得到一个普通的白色椭圆,我需要检测中间有字符的椭圆然后计算白色像素
-
如果您可以发布图片,那将会很有帮助。否则,我不明白为什么中间有文字会影响最外面的轮廓。
标签: c++ opencv image-processing feature-detection feature-extraction