簡體   English   中英

如何有效地計算每個多邊形區域內的所有非零像素?

[英]How to count all non-zero pixels within each polygon area efficiently?

我想有效地計算每個多邊形區域內所有白色像素的數量。

鑒於一些過程:

// some codes for reading gray image
// cv::Mat gray = cv::imread("gray.jpg");

// given polygons
// vector< vector<cv::Point> > polygons;

cv::Mat cropped;
cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
cv::fillPoly(mask, polygons, cv::Scalar(255));
cv::bitwise_and(gray, gray, cropped, mask);

cv::Mat binary;
cv::threshold(cropped, binary, 20, 255, CV_THRESH_BINARY);

所以到目前為止,我們可以得到一個具有多個多邊形區域(假設我們有 3 個區域)的圖像,這些區域具有白色(值為 255)像素。 然后經過一些操作,我們希望得到一個向量,如:

// some efficient operations
// ...

vector<int> pixelNums;

pixelNums 的大小應與多邊形相同,此處為 3。 如果我們打印它們,我們可能會得到一些輸出(這些值基本上取決於預處理):

index: 0; value: 120
index: 1; value: 1389
index: 2; value: 0

這是我的想法。 cv::countNonZero幫助下計算每個多邊形區域內的每個像素,但我需要在循環中調用它,我認為這不是一種有效的方法,不是嗎?

vector<int> pixelNums;
for(auto polygon : polygons)
{
  vector< vector<cv::Point> > temp_polygons;
  temp_polygons.push_back(polygon);

  cv::Mat cropped;
  cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
  cv::fillPoly(mask, temp_polygons, cv::Scalar(255));
  cv::bitwise_and(gray, gray, cropped, mask);

  cv::Mat binary;
  cv::threshold(cropped, binary, 20, 255, CV_THRESH_BINARY);

  pixelNums.push_back(cv::countNonZero(binary));
}

如果您有更好的方法,請回復此帖子。 在這里我說better way是在 cpu 環境中消耗盡可能少的時間。

有一些小的改進可以做,但所有這些結合起來應該可以提供不錯的加速。

  1. 只計算一次閾值
  2. 對較小的圖像進行大多數操作,使用多邊形的邊界框來獲取感興趣的區域
  3. 避免在 for 循環中出現不需要的副本,使用const auto&

示例代碼:

#include <vector>
#include <opencv2/opencv.hpp>

int main()
{
    // Your image
    cv::Mat1b gray = cv::imread("path/to/image", cv::IMREAD_GRAYSCALE);

    // Your polygons
    std::vector<std::vector<cv::Point>> polygons
    {
        { {15,120}, {45,200}, {160,160}, {140, 60} },
        { {10,10}, {15,30}, {50,25}, {40, 15} },
        // etc...
    };

    // Compute the threshold just once
    cv::Mat1b thresholded = gray > 20;

    std::vector<int> pixelNums;
    for (const auto& polygon : polygons)
    {
        // Get bbox of polygon
        cv::Rect bbox = cv::boundingRect(polygon);

        // Make a new (small) mask 
        cv::Mat1b mask(bbox.height, bbox.width, uchar(0));
        cv::fillPoly(mask, std::vector<std::vector<cv::Point>>{polygon}, cv::Scalar(255), 8, 0, -bbox.tl());

        // Get crop
        cv::Mat1b cropped = thresholded(bbox) & mask;

        // Compute the number of white pixels only on the crop
        pixelNums.push_back(cv::countNonZero(cropped));
    }

    return 0;
}

暫無
暫無

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

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