如何使用蒙版从轮廓图像中获取像素值?

时间:2019-02-26 08:50:22

标签: c++ opencv

我试图从轮廓图像中提取平均像素值(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;

}

我得到了正确的图像,如下所示。

enter image description here

我只想读取黄色部分的像素值,而不要读取蒙版外部的像素值。

我还有另一个代码可以读取黄色部分的像素值,但结果却相同。

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

}

请帮助我修改错误。

谢谢。

3 个答案:

答案 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)

  1. 阅读有关cv::Mat::at的信息:第一行,第二栏。不是(x,y)!

  2. cv::mean上见:它可以与遮罩配合使用。

  3. 右初始化:double b = 0.0,g = 0.0,r = 0.0;

  4. int corow = 0;如果mask> 0,则在内部循环++。