簡體   English   中英

如何從帶遮罩的輪廓圖像中獲取像素值?

[英]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);

  1. 閱讀cv::Mat::at :第一行,第二列。 不是(x,y)!

  2. cv::mean上見:它可以與掩碼一起使用。

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

  4. int corow = 0; 如果掩碼 > 0,則在循環 ++corow 內。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM