[英]How to get pixel value from the contoured image with mask?
我試圖從輪廓圖像中提取平均像素值(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
}
請幫我修改錯誤。
先感謝您。
一些東西:
Mat
類型至少令人困惑。 為變量使用適當的名稱,並盡可能使用Mat_<T>
(我總是說)。cv::mean
cv::waitKey()
才能真正看到你的cv::imshow
檢查代碼:
#include <opencv2\opencv.hpp>
int main()
{
cv::Mat3b star = cv::imread("path/to/image");
cv::imshow("Original", star);
cv::Mat3b hsv;
cv::cvtColor(star, hsv, cv::COLOR_BGR2HSV);
cv::Mat1b mask;
cv::inRange(hsv, cv::Scalar(29, 220, 220), cv::Scalar(30, 255, 255), mask);
cv::imshow("mask", mask);
// Change to 'false' to see how to use the 'cv::mask' approach
if (true)
{
double blue, green, red = 0.0;
int counter = 0;
for (int r = 0; r < star.rows; r++)
{
for (int c = 0; c < star.cols; c++)
{
if (mask(r, c) > 0)
{
++counter;
blue += star(r, c)[0];
green += star(r, c)[1];
red += star(r, c)[2];
}
}
}
// Avoid division by 0
if (counter > 0)
{
blue /= counter;
green /= counter;
red /= counter;
}
std::cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
std::cout << "avg_R: " << red << " \n";
std::cout << "avg_G: " << green << " \n";
std::cout << "avg_B: " << blue << " \n\n";
}
else
{
cv::Scalar mean_value = cv::mean(star, mask);
double blue = mean_value[0];
double green = mean_value[1];
double red = mean_value[2];
std::cout << "$$ Red(R), Green(G), Blue(B) $$" << " \n\n";
std::cout << "avg_R: " << red << " \n"; // red value
std::cout << "avg_G: " << green << " \n"; // green value
std::cout << "avg_B: " << blue << " \n\n"; // blue value
}
cv::waitKey();
}
我在您的代碼中看到幾個錯誤:
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 類型,那么您復制到一個頻道? (CV_8U 中的 C1 表示一個通道)。 然后你使用star.type()
,其中要設置的值應該是......你也做了一個掩碼的平均值,這會給你一個只有一個通道集的標量,因為它是一個 CV_8UC1 類型的二進制圖像。 ..要讓它工作,它應該是:
cv::Mat result = cv::Mat(star.rows, star.cols, star.type(), cv::Scalar::all(0));
star.copyTo(result, mask);
cv::Scalar temp = mean(result);
對於第二部分,可以像這樣添加它,但是如果您還沒有修復之前的錯誤......我認為它應該在某些時候給您分段錯誤或如果您幸運的話,會得到奇怪的結果。 最后的結果部分是這樣的:
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
但 corow 應該是面具的非零點,所以它應該是:
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
如果不是,它會給你一個較小的數字,因為它被一個數字划分,其中包括沒有貢獻的黑點。
作為一個額外的注意,你應該使用更多的 OpenCV 函數......在這種情況下cv::mean
做同樣的事情,如果不是,你可以用 sum 和 Division 來簡化它,如:
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
這是假設你做了star.copyTo(result, mask);
線
閱讀cv::Mat::at :第一行,第二列。 不是(x,y)!
在cv::mean上見:它可以與掩碼一起使用。
右初始化:double b = 0.0, g = 0.0, r = 0.0;
int corow = 0; 如果掩碼 > 0,則在循環 ++corow 內。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.