我无法提出任何与您提出的方法大不相同的方法。然而,我能够进行一些计时,这可能有助于指导您的决策。所有计时都在iMac上运行,针对1280*720像素大小的图像,限制为寻找100个轮廓。计时在您的计算机上当然会有所不同,但相对计时应该是有用的。
对于每个测试用例,声明如下:
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
方法一:19.0毫秒
方法一在概念上是最简单的,但也是最慢的。通过为每个轮廓分配唯一的颜色来标记每个轮廓。通过遍历图像中的每个像素,对每个标记组件的值进行求和。
for (size_t i = 0; i < cont.size(); ++i)
{
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;
}
else
{
label -= 1;
}
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];
}
方法三:15.7毫秒
未经修改的方法三具有最简单的实现方式,并且速度最快。所有轮廓都被填充以用作查找平均值的掩码。计算每个轮廓的边界矩形,然后在边界框内使用掩码计算平均值。
警告:如果任何其他轮廓位于所需轮廓的边界矩形内,则此方法将给出不正确的结果。
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];
}
修改后的方法3:17.8毫秒
对方法3进行轻微修改会稍微增加执行时间,但可以获得正确结果无论轮廓位置如何。每个轮廓都被单独标记,并且只使用该轮廓的掩码计算平均值。
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];
}