简体   繁体   English

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

[英]OpenCV - Mean of Mat object in C++

How can we get the mean of an input RGB image(3 dimensional Mat object) so that we get a gray image? 我们如何获得输入RGB图像(3维Mat对象)的均值,从而获得灰度图像? The cvtColor() function of OpenCV converts the image to gray based on a pre-existing formula. OpenCV的cvtColor()函数根据预先存在的公式将图像转换为灰度。 I want to get the mean of all three channels and store the resultant image in another matrix. 我想获取所有三个通道的均值并将结果图像存储在另一个矩阵中。 The cv::mean() function in OpenCV returns the scalar mean of all input channels. OpenCV中的cv::mean()函数返回所有输入通道的标量平均值。

Were this Python, with img being a RGB image, img.mean(2) would get me what I want. 如果是这个Python,并且img是RGB图像,则img.mean(2)会给我我想要的东西。 Successive calls of the addWeighted() function and using gray= blue/3.0 + red/3.0 +green/3.0 [ After splitting channels] yielded different results when compared with Python. 与Python相比,连续调用addWeighted()函数并使用gray= blue/3.0 + red/3.0 +green/3.0 [分割通道后]产生了不同的结果。

Is there anything analogous to img.mean(2) in C++ or the OpenCV library of C++? 有什么类似于C ++或C ++的OpenCV库中的img.mean(2)吗?

Is there anything analogous to img.mean(2) in C++ or the OpenCV library of C++? 有什么类似于C ++或C ++的OpenCV库中的img.mean(2)吗?

No, but you can easily compute that. 不,但是您可以轻松地进行计算。 There are a few ways of doing it: 有几种方法可以做到:

  1. Loop over all the image, and set each value as the mean of the input pixel values. 循环遍历所有图像,并将每个值设置为输入像素值的平均值。 Take care of computing the intermediate values for the mean on a type with more capacity and accuracy than uchar (here I used double ) or you may end up with wrong results. 请注意计算类型的均值的中间值,该类型的能力和准确性要比uchar (在这里我使用double )更大,否则您可能会得到错误的结果。 You can also optimize the code further, eg see this question and its answers. 您还可以进一步优化代码,例如查看此问题及其答案。 You just need to change the function computed in the inner loop to compute the mean. 您只需要更改在内循环中计算的函数即可计算均值。

  2. Use reduce . 使用reduce You can reshape you 3 channel matrix of size rows x cols to be a matrix of shape ((rows*cols) x 3), and then you can use the reduce operation with parameter REDUCE_AVG to compute the average row-wise. 您可以将rows x cols 3个通道矩阵reshape整形为形状为((rows * cols)x 3)的矩阵,然后可以对参数REDUCE_AVG使用reduce操作来计算平均行数。 Then reshape the matrix to correct size. 然后将矩阵reshape为正确的大小。 reshape operation is very fast, since you just modify the header without affecting the stored data. reshape操作非常快,因为您只需修改标题就不会影响存储的数据。

  3. Use matrix operations to sum channels. 使用矩阵运算对通道求和。 You can use split to get the matrix for each channel, and sum them. 您可以使用split来获取每个通道的矩阵,并对它们求和。 Take care to not saturate your values while summing up! 总结时请注意不要使您的价值观饱和! (Thanks to beaker for this one.) (感谢烧杯 。)

You can see that the first approach is faster with small matrices, but as soon as the size increase, the second approach performs much better since you take advantage of OpenCV optimizations. 您可以看到,对于较小的矩阵,第一种方法速度更快,但是一旦大小增加,第二种方法的性能就会好得多,因为您可以利用OpenCV优化。 The third approach works surprisingly well (thanks to matrix expressions). 第三种方法出奇地好(由于矩阵表达式)。

Some numbers, time in ms. 一些数字,时间以毫秒为单位。 Time may vary on you computer depending on OpenCV optimizations enabled. 您的计算机上的时间可能会有所不同,具体取决于启用的OpenCV优化。 Run in release! 在发行版中运行!

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

Code: 码:

#include <opencv2\opencv.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() 意思()

Calculates an average (mean) of array elements. 计算数组元素的平均值。

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

Python: cv2.mean(src[, mask]) → retval Python: cv2.mean(src [,mask])→retval

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

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

Parameters: src – input array that should have from 1 to 4 channels so that the result can be stored in Scalar_ . 参数: src –输入数组,应该具有1到4个通道,以便可以将结果存储在Scalar_中。 mask – optional operation mask. 遮罩–可选的操作遮罩。

The function mean calculates the mean value M of array elements, independently for each channel, and return it: 函数mean对每个通道独立地计算数组元素的平均值M,然后将其返回:

When all the mask elements are 0's, the functions return Scalar::all(0) . 当所有mask元素均为0时,函数返回Scalar :: all(0)。

Also check this answer how to calculate and use cvMat mean value 还要检查此答案如何计算和使用cvMat平均值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM