OpenCV-C++中Mat对象的平均值

OpenCV - Mean of Mat object in C++

本文关键字:平均值 对象 Mat OpenCV-C++      更新时间:2023-10-16

我们如何获得输入RGB图像(三维Mat对象)的平均值,从而获得灰色图像?OpenCV的cvtColor()函数基于预先存在的公式将图像转换为灰色。我想得到所有三个通道的平均值,并将结果图像存储在另一个矩阵中。OpenCV中的cv::mean()函数返回所有输入通道的标量平均值。

如果这是Python,img是RGB图像,img.mean(2)会得到我想要的。与Python相比,连续调用addWeighted()函数和使用gray= blue/3.0 + red/3.0 +green/3.0[分割通道后]会产生不同的结果。

在C++或C++的OpenCV库中有类似img.mean(2)的东西吗?

在C++或C++的OpenCV库中有类似于img.mean(2)的东西吗?

没有,但你可以很容易地计算出来。有几种方法可以做到这一点:

  1. 在所有图像上循环,并将每个值设置为输入像素值的平均值。注意计算一个比uchar(这里我使用的是double)容量和精度更高的类型的平均值的中间值,否则可能会得到错误的结果。您还可以进一步优化代码,例如,查看此问题及其答案。您只需要更改内环中计算的函数即可计算平均值。

  2. 使用reduce。您可以将大小为rows x cols的3通道矩阵reshape设为形状为((rows*cols)x3)的矩阵,然后您可以使用参数为REDUCE_AVGreduce运算来计算平均行数。然后CCD_ 15对矩阵进行大小校正。reshape操作非常快,因为您只需修改标头而不会影响存储的数据。

  3. 使用矩阵运算求和通道。您可以使用split来获得每个通道的矩阵,并对它们求和。在总结的时候注意不要让你的价值观饱和(感谢烧杯。)

您可以看到,第一种方法在使用小矩阵时速度更快,但一旦大小增加,第二种方法的性能就会更好,因为您利用了OpenCV优化。第三种方法效果出奇地好(多亏了矩阵表达式)。

一些数字,时间以毫秒为单位。根据启用的OpenCV优化,您的计算机上的时间可能会有所不同。磨合释放!

Size  : 10x10   100x100   1000x1000   10000x10000
Loop  : 0.0077  0.3625    34.82       3456.71
Reduce: 1.44    1.42      8.88        716.75
Split : 0.1158  0.0656    2.26304     246.476

代码:

#include <opencv2opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat3b img(1000, 1000);
randu(img, Scalar(0, 0, 0), Scalar(10, 10, 10));

{
double tic = double(getTickCount());
Mat1b mean_img(img.rows, img.cols, uchar(0));
for (int r = 0; r < img.rows; ++r) {
for (int c = 0; c < img.cols; ++c) {
const Vec3b& v = img(r, c);
mean_img(r, c) = static_cast<uchar>(round((double(v[0]) + double(v[1]) + double(v[2])) / 3.0));
}
}
double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
cout << "Loop: " << toc << endl;
}
{
double tic = double(getTickCount());
Mat1b mean_img2 = img.reshape(1, img.rows*img.cols);
reduce(mean_img2, mean_img2, 1, REDUCE_AVG);
mean_img2 = mean_img2.reshape(1, img.rows);
double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
cout << "Reduce: " << toc << endl;
}
{
double tic = double(getTickCount());
vector<Mat1b> planes;
split(img, planes);
Mat1b mean_img3;
if (img.channels() == 3) {
mean_img3 = (planes[0] + planes[1] + planes[2]) / 3.0;
}
double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
cout << "Split: " << toc << endl;
}

getchar();
return 0;
}

mean()

计算数组元素的平均值。

C++:标量均值(InputArray src,InputArray mask=noArray())

Python:cv2.mean(src[,mask])→重新评估

C:CvScalar cvAvg(const CvArr*arr,const Cv4Arr*mask=NULL)

Python:cv.Avg(arr,mask=None)→标量

参数:src–应该有1到4个通道的输入数组,以便将结果存储在Scalar_中。mask–可选操作掩码。

函数平均值计算阵列元素的平均值M,独立于每个通道,并返回:

当所有掩码元素都是0时,函数返回Scalar::all(0)。

还要检查这个答案如何计算和使用cvMat平均值