我试图从轮廓图像中提取平均像素值(R,G,B)。但是,我的问题是,当我应用下面的代码时,观察到一些奇怪的值。
int main(){
cv::Mat star = imread("C:\\Users\\PC\\Desktop\\star\\starcircle.png");
cv::Mat mask = cv::Mat::zeros(star.rows, star.cols, CV_8UC1);
cv::Mat frame;
double b, g, r = 0.0;
cv::imshow("Original", star);
cv::cvtColor(star, frame, CV_BGR2HSV);
cv::inRange(frame, cv::Scalar(29, 220, 220), cv::Scalar(30, 255, 255), mask);
cv::imshow("mask", mask);
cv::Mat result = cv::Mat(star.rows, star.cols, CV_8UC1, star.type());
result.setTo(cv::Scalar(0, 0, 0));
star.copyTo(result, mask);
cv::Scalar temp = mean(mask);
cout << "avg_R: " << temp[2] << " \n"; // red value
cout << "avg_G: " << temp[1] << " \n"; // green value
cout << "avg_B: " << temp[0] << " \n\n"; // blue value
cv::imshow("result", result);
cv::waitKey(-1);
return 0;
}
我得到了正确的图像,如下所示。
我只想读取黄色部分的像素值,而不要读取蒙版外部的像素值。
我还有另一个代码可以读取黄色部分的像素值,但结果却相同。
int main(){
cv::Mat star = imread("C:\\Users\\PC\\Desktop\\star\\starcircle.png");
cv::Mat mask = cv::Mat::zeros(star.rows, star.cols, CV_8UC1);
cv::Mat frame;
double b, g, r = 0.0;
cv::imshow("Original", star);
cv::cvtColor(star, frame, CV_BGR2HSV);
cv::inRange(frame, cv::Scalar(29, 220, 220), cv::Scalar(30, 255, 255), mask);
cv::imshow("mask", mask);
cv::Mat result = cv::Mat(star.rows, star.cols, CV_8UC1, star.type());
result.setTo(cv::Scalar(0, 0, 0));
star.copyTo(result, mask);
int hei = star.rows;
int wid = star.cols;
int corow = hei * wid;
double b, g, r = 0.0;
for (int x = 0; x < hei; x++) {
for (int y = 0; y < wid; y++) {
if (mask.at<unsigned char>(x, y) > 0) {
b += result.at<Vec3b>(x, y)[0];
g += result.at<Vec3b>(x, y)[1];
r += result.at<Vec3b>(x, y)[2];
}
else {
}
}
}
cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
cout << "avg_R: " << r / corow << " \n"; // red value
cout << "avg_G: " << g / corow << " \n"; // green value
cout << "avg_B: " << b / corow << " \n\n"; // blue value
}
请帮助我修改错误。
谢谢。
答案 0 :(得分:2)
几件事:
PrintList(QMetaObject*)
类型至少令人困惑。为变量使用适当的名称,并尽可能使用Mat
(我会一直说)。Mat_<T>
cv::mean
才能真正看到您的cv::waitKey()
检查代码:
cv::imshow
答案 1 :(得分:1)
我在您的代码中看到几个错误:
Edge<WNode>
如果结果为CV_8UC1类型,那么您将复制到一个通道吗? (CV_8U中的C1表示一个通道)。然后,使用cv::Mat result = cv::Mat(star.rows, star.cols, CV_8UC1, star.type());
result.setTo(cv::Scalar(0, 0, 0));
star.copyTo(result, mask);
cv::Scalar temp = mean(mask);
,其中要设置的值应为...。还要对掩码进行均值处理,因为它是CV_8UC1类型的二进制图像,所以它只给您一个标量,并且只设置了一个通道。 ..要使其正常工作,应该是:
star.type()
对于第二部分,可以像这样添加它,但是,如果您还没有解决之前的错误,我想它应该会在某些时候给您带来细分错误,或者如果您很幸运的话,还会出现怪异的结果。最后,您拥有的结果部分是这样的:
cv::Mat result = cv::Mat(star.rows, star.cols, star.type(), cv::Scalar::all(0));
star.copyTo(result, mask);
cv::Scalar temp = mean(result);
但是corow应该是蒙版的非零点,所以应该是:
cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
cout << "avg_R: " << r / corow << " \n"; // red value
cout << "avg_G: " << g / corow << " \n"; // green value
cout << "avg_B: " << b / corow << " \n\n"; // blue value
如果不是的话,它会给你一个较小的数字,因为它被一个包括不起作用的黑点的数字所除。
需要特别注意的是,您应该使用更多的OpenCV函数...在这种情况下,corow = cv::countNonZero(mask);
cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
cout << "avg_R: " << r / corow << " \n"; // red value
cout << "avg_G: " << g / corow << " \n"; // green value
cout << "avg_B: " << b / corow << " \n\n"; // blue value
会做同样的事情,否则,您可以使用求和和除法来简化它,例如:
cv::mean
这是假设您做了 cv::Scalar summed = cv::sum(result);
cv::Scalar mean = summed / static_cast<double>(cv::countNonZero(mask));
std::cout << "$$ Red(R), Green(G), Blue(B) $$" << std::endl << std::endl;
std::cout << "avg_R: " << mean[2] << std::endl; // red value
std::cout << "avg_G: " << mean[1] << std::endl; // green value
std::cout << "avg_B: " << mean[0] << std::endl << std::endl; // blue value
行
答案 2 :(得分:-1)
阅读有关cv::Mat::at的信息:第一行,第二栏。不是(x,y)!
在cv::mean上见:它可以与遮罩配合使用。
右初始化:double b = 0.0,g = 0.0,r = 0.0;
int corow = 0;如果mask> 0,则在内部循环++。