How to find average intensity of OpenCV contour in realtime

僤鯓⒐⒋嵵緔 提交于 2019-12-04 05:19:23

I was unable to come up with any methods substantially different than your suggested approaches. However, I was able to do some timings that may help guide your decision. All of my timings were run on a 1280*720 image on an iMac, limited to finding 100 contours. The timings will of course be different on your machine, but the relative timings should be informative.

For each test case, the following are declared:

std::vector<std::vector<cv::Point>> cont;  // Filled by cv::findContours()
cv::Mat labels = cv::Mat::zeros(image.size(), CV_8UC1);     
std::vector<float> cont_avgs(cont.size(), 0.f); // This contains the averages of each contour

Method 1: 19.0ms

Method 1 is conceptually the simplest, but it is also the slowest. Each contour is labeled by assigning a unique color to each contour. Values of each labelled component are summed by iterating through every pixel in the image.

for (size_t i = 0; i < cont.size(); ++i)
{
    // Labels starts at 1 because 0 means no contour
    cv::drawContours(labels, cont, i, cv::Scalar(i+1), CV_FILLED);
}

std::vector<float> counts(cont.size(), 0.f);
const int width = image.rows;
for (size_t i = 0; i < image.rows; ++i)
{
    for (size_t j = 0; j < image.cols; ++j)
    {
        uchar label = labels.data[i*width + j];

        if (label == 0)
        {
            continue;   // No contour
        }
        else
        {
            label -= 1; // Make labels zero-indexed
        }

        uchar value = image.data[i*width + j];
        cont_avgs[label] += value;
        ++counts[label];
    }
}
for (size_t i = 0; i < cont_avgs.size(); ++i)
{
    cont_avgs[i] /= counts[i];
}

Method 3: 15.7ms

An unmodified Method 3 has the simplest implementation and is also the fastest. All contours are filled to use as a mask for finding the mean. The bounding rectangle of each contour is computed, and then the mean is calculated using the mask within the bounding box.

Warning: This method will give incorrect results if any other contours are within the bounding rectangle of the contour of interest.

cv::drawContours(labels, cont, -1, cv::Scalar(255), CV_FILLED);

for (size_t i = 0; i < cont.size(); ++i)
{
    cv::Rect roi = cv::boundingRect(cont[i]);
    cv::Scalar mean = cv::mean(image(roi), labels(roi));
    cont_avgs[i] = mean[0];
}

Modified Method 3: 17.8ms

Making slight modifications to Method 3 increases execution time slightly, but gains the benefit of giving correct results regardless of contour positions. Each contour is individually labeled, and the mean is calculated using only the mask for that contour.

for (size_t i = 0; i < cont.size(); ++i)
{
    cv::drawContours(labels, cont, i, cv::Scalar(i), CV_FILLED);
    cv::Rect roi = cv::boundingRect(cont[i]);
    cv::Scalar mean = cv::mean(image(roi), labels(roi) == i);
    cont_avgs[i] = mean[0];
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!