我们可以将数字图像理解成一定尺寸的矩阵,矩阵中每个元素的大小表示了图像中每个像素的亮暗程度,因此统计矩阵中的最大值,就是寻找图像中灰度值最大的像素,计算平均值就是计算图像像素平均灰度,可以用来表示图像整体的亮暗程度。因此针对矩阵数据的统计工作在图像像素中同样具有一定的意义和作用。在OpenCV 4中集成了求取图像像素最大值、最小值、平均值、均方差等众多统计量的函数,接下来将详细介绍这些功能的相关函数。
OpenCV 4提供了寻找图像像素最大值、最小值的函数minMaxLoc(),该函数的原型在代码清单3-7中给出。
void cv::minMaxLoc(InputArray src,
double * minVal,
double * maxVal = 0,
Point * minLoc = 0,
Point * maxLoc = 0,
InputArray mask = noArray())
该函数实现的功能是寻找图像中特定区域内的最值,函数第一个参数是输入单通道矩阵,需要注意的是,该变量必须是一个单通道的矩阵数据,如果是多通道的矩阵数据,需要用cv::Mat::reshape()将多通道变成单通道,或者分别寻找每个通道的最值,然后再进行比较寻找到全局最值。对于cv::Mat::reshape()的用法,在代码清单3-8中给出。第二到第五个参数分别是指向最小值、最大值、最小值位置和最大值位置的指针,如果不需要寻找某一个参数,可以将该参数设置为NULL,函数最后一个参数是寻找最值得掩码矩阵,用于标记寻找上述四个值的范围,参数默认值为noArray(),表示寻找范围是矩阵中所有数据。
Mat cv::Mat::reshape(int cn,int rows = 0)
#include
#include
#include
#include
#include "opencv/highgui.h"
using namespace std;
using namespace cv;
int main(int argc,char** argv) {
cout<<"OpenCv Version: "<<CV_VERSION<<endl;
float a[12]={1,2,3,4,5,10,6,7,8,9,10,0};
Mat img=Mat(3,4,CV_32FC1,a);//单通道矩阵
Mat imgs=Mat(2,3,CV_32FC2,a);//多通道矩阵
double minVal,maxVal;//用于存放矩阵中的最大值和最小值
Point minIdx,maxIdx;//用于存放矩阵中的最大值和最小值的位置
/*寻找单通道矩阵中的最值*/
minMaxLoc(img,&maxVal,&minVal,&minIdx,&maxIdx);
cout << "img中最大值是:" << maxVal << " " << "在矩阵中的位置:" << maxIdx << endl;
cout << "img中最小值是:" << minVal << " " << "在矩阵中的位置:" << minIdx << endl;
/*寻找多通道矩阵中的最值*/
Mat imgs_re=imgs.reshape(1,4);//将多通道矩阵变成单通道矩阵
minMaxLoc(imgs_re,&minVal,&maxVal,&minIdx,&maxIdx);
cout << "img中最大值是:" << maxVal << " " << "在矩阵中的位置:" << maxIdx << endl;
cout << "img中最小值是:" << minVal << " " << "在矩阵中的位置:" << minIdx << endl;
return 0;
}
图像的均值表示图像整体的亮暗程度,图像的均值越大图像整体越亮。标准方差表示图像中明暗变化的对比程度,标准差越大表示图像中明暗变化越明显。OpenCV 4提供了mean()函数用于计算图像的平均值,提供了meanStdDev()函数用于同时计算图像的均值和标准方差。接下来将详细的介绍这两个函数的使用方法。
cv::Scalar cv::mean(InputArray src,InputArray mask = noArray())
该函数用来求取图像矩阵的每个通道的平均值,函数的第一个参数用来输入待求平均值的图像矩阵,其通道数目可以在1到4之间。需要注意的是,该函数的返回值是一个cv::Scalar类型的变量,函数的返回值有4位,分别表示输入图像4个通道的平均值,如果输入图像只有1个通道,那么返回值的后三位都为0,例如输入该函数一个单通道平均值为1的图像,输出的结果为[1,0,0,0],可以通过cv::Scalar[n]查看第n个通道的平均值。该函数的第二个参数用于控制图像求取均值的范围,在第一个参数中去除第二个参数中像素值为0的像素,计算的原理如式(3.5)所示,当不输入第二个参数时,表示求取第一个参数全部像素的平均值。
其中表示第c个通道的平均值,表示第c个通道像素的灰度值。
meanStdDev()函数可以同时求取图像每个通道的平均值和标准方差,其函数原型在代码清单3-11中给出。
void cv::meanStdDev(InputArray src,OutputArray mean,OutputArray stddev,InputArray mask = noArray())
该函数的第一个参数与前面mean()函数第一个参数相同,都可以是1-4通道的图像,不同之处在于该函数没有返回值,图像的均值和标准方差输出在函数的第二个和第三个参数中,区别于mean()函数,用于存放平均值和标准方差的是Mat类型变量,变量中的数据个数与第一个参数通道数相同,如果输入图像只有一个通道,该函数求取的平均值和标准方差变量中只有一个数据。该函数计算原理如式(3.6)所示。
我们在代码清单3-12中给出了利用上面两个函数计算代码清单3-9中img和imgs两个矩阵的平均值和标准方差,并在图3-8给出了程序运行的结果。
#include
#include
#include
#include
#include "opencv/highgui.h"
using namespace std;
using namespace cv;
int main(int argc,char** argv) {
cout<<"OpenCv Version: "<<CV_VERSION<<endl;
float a[12]={1,2,3,4,5,10,6,7,8,9,10,0};
Mat img=Mat(3,4,CV_32FC1,a);//单通道矩阵
Mat imgs=Mat(2,3,CV_32FC2,a);//多通道矩阵
cout << "/* 用meanStdDev同时求取图像的均值和标准方差 */" << endl;
Scalar myMean;
myMean=mean(imgs);
cout<<"imgs均值 = "<<myMean<<endl;
cout<<"imgs第一个通道的均值 = "<<myMean[0]<<" "
<<"imgs第二个通道的均值 = "<<myMean[1]<<endl;
cout << "/* 用meanStdDev同时求取图像的均值和标准方差 */" << endl;
Mat myMeanMat,myStddevMat;
meanStdDev(img,myMeanMat,myStddevMat);
cout << "img均值=" << myMeanMat << " " << endl;
cout << "img标准方差=" << myStddevMat << endl << endl;
meanStdDev(imgs,myMeanMat,myStddevMat);
cout << "img均值=" << myMeanMat << " " << endl;
cout << "img标准方差=" << myStddevMat << endl << endl;
return 0;
}