文章目录
OpenCV 中的一些基础操作
1.相关数据结构,Mat,Scalar,Vec
2.Mat操作
3.ROI操作,取某行某列之类…
4.获得程序运行时间,生成随机数
5.矩阵运算
/*头文件*/
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
1.OpenCV基本数据结构
1.0 type
1.0.1
float: 4字节,6-7位有效数字 -3.4E-38 到 3.4E38
double: 8字节,15~16位有效数字 -1.7E-308 到 1.7E308
在OpenCV里面,许多数据结构为了达到內存使用的最优化,通常都会用它最小上限的空间来分配变量,有的数据结构也会因为图像文件格式的关系而给予适当的变量,因此需要知道它们声明的空间大小来配置适当的变量。一 般标准的图片,为RGB格式它们的大小为8bits格式,范围为0~255,对一个int空间的类型来说实在是太小,整整浪费了24bits的空间,假设有个640480的BMP文件空间存储內存,那整整浪费了6404803(32-8)bits的內存空间,总共浪费了2.6MB!,也就是那 2.6MB内什么东西都没存储,如果今天以8bits的格式来存储则只使用到0.6MB的內存而已(6404803*(8)+54 bits),因此,对于文件格式的对应是一件很重要的事。
在这边除了要考虑bits的空间大小外,还要考虑使用类型的正负号的问题,一般的图像文件是不存在负号的,如果今天即使选则正确的空间大小,可是出现的结果却是负的,那就功亏一篑了。这里除了Float及double类型,char,int,short int都是用二的补数表示法,它们不具正负号bit,而Float,double则是用IEEE 754,在第32bit,64bit上有一个正负号bit.
1.Unsigned 8bits(一般的图像文件格式使用的大小)
CvMat数据结构参数:CV_8UC1,CV_8UC2,CV_8UC3,CV_8UC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
uchar | 8bits | 0~255 | (OpenCV缺省变量,同等unsigned char) |
unsigned char | 8bits | 0~255 |
2.Signed 8bits
CvMat数据结构参数:CV_8SC1,CV_8SC2,CV_8SC3,CV_8SC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
char | 8bits | -128~127 |
3.Unsigned 16bits
IplImage数据结构参数:IPL_DEPTH_16U
CvMat数据结构参数:CV_16UC1,CV_16UC2,CV_16UC3,CV_16UC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
ushort | 16bits | 0~65535 | (OpenCV缺省变量,同等unsigned short int) |
unsigned short int | 16bits | 0~65535 | (unsigned short) |
4.Signed 16bits
CvMat数据结构参数:CV_16SC1,CV_16SC2,CV_16SC3,CV_16SC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
short int | 16bits | -32768~32767 | (short) |
5.Signed 32bits
CvMat数据结构参数:CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
int | 32bits | -2147483648~2147483647 | (long) |
6.Float 32bits
IplImage数据结构参数:IPL_DEPTH_32F
CvMat数据结构参数:CV_32FC1,CV_32FC2,CV_32FC3,CV_32FC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
float | 32bits | 1.1810-38~3.401038 |
7.Double 64bits
CvMat数据结构参数:CV_64FC1,CV_64FC2,CV_64FC3,CV_64FC4
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
double | 64bits | 2.2310-308~1.7910308 |
8.Unsigned 1bit
IplImage数据结构参数:IPL_DEPTH_1U
变量类型 | 空间大小 | 范围 | 其他 |
---|---|---|---|
bool | 1bit | 0~1 |
1.0.2
数据类型及其取值范围
数值 | 具体类型 | 取值范围 |
---|---|---|
CV_8U | 8 位无符号整数 | (0……255) |
CV_8S | 8 位符号整数 | (-128……127) |
CV_16U | 16 位无符号整数 | (0……65535) |
CV_16S | 16 位符号整数 | (-32768……32767) |
CV_32S | 32 位符号整数 | (-2147483648……2147483647) |
CV_32F | 32 位浮点数 | (-FLT_MAX ………FLT_MAX,INF,NAN) |
CV_64F | 64 位浮点数 | (-DBL_MAX ……….DBL_MAX,INF,NAN) |
在以下两个场景中使用 OpenCV 时,我们必须事先知道矩阵元素的数据类型:
- 使用
at
方法访问数据元素的时候要指明数据类型 - 做数值运算的时候,比如究竟是整数除法还是浮点数除法。
但面对一大堆代码,我们有时并不清楚当前的矩阵元素究竟是什么类型,这篇文章就是以 cv::Mat
类为例来解决这个问题。
cv::Mat 类的对象有一个成员函数 type()
用来返回矩阵元素的数据类型,返回值是 int
类型,不同的返回值代表不同的类型。OpenCV Reference Manual 中对 type()
的解释如下所示:
Mat::type
C++: int Mat::type() const
The method returns a matrix element type. This is an identifier compatible with the CvMat type system, like CV_16SC3 or 16-bit signed 3-channel array, and so on.
实际的代码如下所示:
cv::Mat haha = cv::Mat::zeros(3,3,CV_64F);
int hahaType = haha.type();
std::cout<<"hahaType = "<<hahaType<<std::endl;
至此,知道了 type()
函数,下一步更关键的就是返回值和具体类型之间的对应关系了。文章《[LIST OF MAT TYPE IN OPENCV][LIST OF MAT TYPE IN OPENCV]》对此整理得非常清楚,具体如下表所示:
C1 | C2 | C3 | C4 | |
---|---|---|---|---|
CV_8U | 0 | 8 | 16 | 24 |
CV_8S | 1 | 9 | 17 | 25 |
CV_16U | 2 | 10 | 18 | 26 |
CV_16S | 3 | 11 | 19 | 27 |
CV_32S | 4 | 12 | 20 | 28 |
CV_32F | 5 | 13 | 21 | 29 |
CV_64F | 6 | 14 | 22 | 30 |
表头的 C1, C2, C3, C4 指的是通道(Channel)数,比如灰度图像只有 1 个通道,是 C1;JPEG格式 的 RGB 彩色图像就是 3 个通道,是 C3;PNG 格式的彩色图像除了 RGB 3个通道外,还有一个透明度通道,所以是 C4。大家还会发现 7 怎么没有被定义类型,这个可以看 OpenCV 源码,有如下所示的一行,说明 7 是用来给用户自定义的:
#define CV_USRTYPE1 7
如果仅仅是为了在数值计算前明确数据类型,那么看到这里就可以了;如果是要使用 at
方法访问数据元素,那么还需要下面一步。因为以单通道为例,at
方法接受的是 uchar
这样的数据类型,而非 CV_8U
。在已知通道数和每个通道数据类型的情况下,指定给 at
方法的数据类型如下表所示:
C1 | C2 | C3 | C4 | C6 | |
---|---|---|---|---|---|
uchar | uchar |
cv::Vec2b |
cv::Vec3b |
cv::Vec4b |
|
short | short |
cv::Vec2s |
cv::Vec3s |
cv::Vec4s |
|
int | int |
cv::Vec2i |
cv::Vec3i |
cv::Vec4i |
|
float | float |
cv::Vec2f |
cv::Vec3f |
cv::Vec4f |
cv::Vec6f |
double | double |
cv::Vec2d |
cv::Vec3d |
cv::Vec4d |
cv::Vec6d |
1.1 Scalar类
Scalar类
short类型的向量
Scalar()表示有四个元素的数组,通常若只用到三个参数如, Scalar(a,b,c),那第四个可以不写出来,
三个参数的顺序是BGR顺序,通常用来Mat类的初始化 CV_8UC3 里面的3表示三通道,就是BGR,
Scalar(a,b,c)也可以给CV_8UC1类型的Mat赋值,只有a传进去
Scalar::all(a):全a
1.2 Size类
Size类
Size(5,5)表示宽度和高度都是5, Size(4,6)指宽 4,高 6,即 6行4列
用来作为一些需要设置高度宽度的函数作为参数
openCV关于宽高,xy容易混淆的地方:
row == heigh == Point.y
col == width == Point.x
Mat::at(Point(x, y)) == Mat::at(y,x)
1.3 Vec类
/*Vec类型 小型向量 定义了不同类型的向量*/
//最常用的是Vec3b,三位无符号整数(0-255)
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
void vec_test()
{
Vec3b vec ={1,2,3};
Vec3b color;
color[0] = 255;
color[1] = 0;
color[2] = 0;
cout << "vec3b..." << vec << endl; //[1, 2, 3]
}
1.4 Mat类
Mat类是OpenCV提供的矩阵类,可以进行很多矩阵操作
1.4.1 Mat的创建
void mat_test()
{
/**
* type可以是 CV_8UC1, CV_16SC1, …, CV_64FC4 等。里面的 8U 表示 8 位无符号整数,
* 16S 表示16 位有符号整数, 64F表示 64 位浮点数(即 double 类型),CV_32F也可表示浮点数(float)
* C 后面的数表示通道数,例如 C1 表示一个通道的图像, C4 表示 4 个通道的图像,以此类推。
* 如果需要更多的通道数,需要用宏 CV_8UC(n)
*/
//Mat有很多种初始化方法 20种
//Mat::Mat()
//Mat(int rows, int cols, int type)
/*
* Mat::Mat(int rows, int cols, int type, const Scalar& s)
创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初
始化为值 s;
*/
//Mat::Mat(Size size, int type,const Scalar& s)
//Mat::Mat(const Mat& m) m 和新对象共用图像数据;
//要想互不影响,使用Mat M2 = M1.clone();或者 Mat M2; M1.copyto(M2);
namedWindow("test",WINDOW_NORMAL);
Mat M0();
Vec3b vec ={1,2,3};
Mat M1(6,4,CV_8UC3,vec);//Vec3b 也可以给Mat赋值
Mat M2(6,4,CV_8UC1,Scalar(125));
Mat M4(M2);
uchar i = 1.4;//最后i=1,只能是整数,四舍五入
/*
* typedef Size_<int> Size2i;
typedef Size_<int64> Size2l;
typedef Size_<float> Size2f;
typedef Size_<double> Size2d;
typedef Size2i Size;
*/
Size size(40,60);//size(4,6)指宽 4,高 6,即 6行4列
Mat M3(size,CV_8UC1,i);//直接uchar i = 0;也可以赋值//灰度图像可以这么赋值,还是用Scalar()方便一点
//zeros()全0、 ones()全1、 eye()单位矩阵
Mat M5=Mat::eye(4, 4, CV_8UC1);
Mat M6(6,4,CV_32FC3,Scalar::all(1.5));//Scalar::all(1.5)全部设为1.5
///小型矩阵 直接输入 使用Mat_()类
Mat small_mat = (Mat_<double>(3,3) << 0,-1,0,-1,5,6,1,4,7.1);
cout << "M1 = \n" << M1 << endl;
cout << "===========================Mat相关操作============================" << endl;
//使用矩阵变量的at()方法来实现对一个像素点数据的读取和赋值
float value1 = M6.at<float>(0,71);
int value2 = (int)M2.at<uchar>(0,0);//想把uchar打印出来,要先转换成int
cout << "M6.at<float>(0.0) = " << value1 << endl
<< "M2.at<uchar>(0,0) = " << value2 << endl;
//imshow("test",M2);
//waitKey(0);
cout << "M6 = \n" << M6 << endl;
M6.at<float>(0,0) = 100;
M6.at<float>(1,12) = 100;//(1,12)第2行第一个开始数,往后第12个元素//按行存储?
cout << "M6 = \n" << M6 << endl;
//读取三通道矩阵 at<Vec3>
cout << M6.at<Vec3f>(0,0)[0] << endl;
cout << M6.at<Vec3f>(0,0)[1] << endl;
cout << M6.at<Vec3f>(0,0)[2] << endl;
//获取行 列 数目
int m_rows = M6.rows;//6
int m_cols = M6.cols;//4
cout << "m_rows = " << m_rows << endl
<< "m_cols = " << m_cols << endl;
}
1.4.2 Mat遍历方法
Mat访问方法:
方法一:
Mat.at<type>(row,col); //type: uchar,Vec3b等
方法二:
指针,把每一行当做 一个数组
type* p = Mat.ptr<type>(i)
返回Mat第i行 首像素 指针 p[j] 即为第i行第j列
方法三:迭代器
MatIterator_<type> it = Mat.begin<type>();
MatIterator_<type> it_end = Mat.end<type>();
for(int i = 0;it != it_end;it ++)
*it
/*三种遍历方法*/
void mat_search()
{
//at()
#if 1
Mat grayim1(600,800,CV_8UC1);
Mat colorim1(600,800,CV_8UC3);
clock_t startTime,endTime;
startTime = clock(); //计时开始
auto start1 = system_clock::now();
//遍历所有像素,并设置像素值
for (int i = 0;i < grayim1.rows;i++)
for(int j = 0;j < grayim1.cols;j++)
{
grayim1.at<uchar>(i,j) = (i + j) % 255;
}
//遍历所有像素,并设置像素值
for (int i = 0;i < colorim1.rows;i++)
for(int j = 0;j < colorim1.cols;j++)
{
Vec3b pixel;
pixel[0] = i % 255; //B
pixel[1] = j % 255; //G
pixel[2] = (i+j)%255; //R
colorim1.at<Vec3b>(i,j) = pixel;
}
endTime = clock(); //计时结束
auto end1 = system_clock::now();
auto time1 = duration_cast<microseconds>(end1 - start1);
cout << "The run time is " << (double)(endTime - startTime) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
cout << "The run time is " << double(time1.count())
* microseconds::period::num / microseconds::period::den *1000 << "ms"<< endl;
imshow("gratim1",grayim1);
imshow("colorim1",colorim1);
waitKey(0);
#endif
//使用迭代器遍历矩阵
#if 1
Mat grayim2(600,800,CV_8UC1);
Mat colorim2(600,800,CV_8UC3);
//遍历所有像素,并设置像素值
auto start2 = system_clock::now();
MatIterator_<uchar> grayit,grayend;
for(grayit = grayim2.begin<uchar>(),grayend = grayim2.end<uchar>();grayend!=grayit;grayit++)
{
*grayit = rand()%255;
}
//遍历所有像素,并设置像素值
MatIterator_<Vec3b> colorit,colorend;
for(colorit = colorim2.begin<Vec3b>(),colorend = colorim2.end<Vec3b>();colorend!=colorit;colorit++)
{
Vec3b color;
color[0] = rand()%255;
color[1] = rand()%255;
color[2] = rand()%255;
*colorit = color;
}
auto end2 = system_clock::now();
auto duration2 = duration_cast<microseconds>(end2 - start2);
double run_time2 = double(duration2.count()) / 1000;
cout << "run time = " << run_time2 << endl;
imshow("grayim2",grayim2);
imshow("colorim2",colorim2);
waitKey(0);
#endif
//使用指针来遍历
#if 1
Mat grayim3(600,800,CV_8UC1);
Mat colorim3(600,800,CV_8UC3);
auto start3 = system_clock::now();
for (int i = 0;i < grayim3.rows;i++)
{
uchar* p = grayim3.ptr<uchar>(i);
for (int j = 0;j < grayim3.cols;j++)
{
p[j] = (i+j) % 255;
}
}
for(int i = 0;i < colorim3.rows;i++)
{
Vec3b* p = colorim3.ptr<Vec3b>(i);
for (int j = 0;j < colorim3.cols;j++)
{
p[j][0] = i % 255;
p[j][1] = j % 255;
p[j][2] = 0;
}
}
auto end3 = system_clock::now();
auto duration3 = duration_cast<microseconds>(end3 - start3);
double run_time3 = double(duration3.count()) / 1000;
cout << "run time = " << run_time3 << endl;
#endif
}
1.4.3 Mat ROI选择
Mat类提供了很多选择局部区域的方法,
但是它们都是指向同一片数据区的,因此就算把局部区域赋值给新的Mat对象,其实还是指向同一个数据区,对这个ROI的操作会反应到原矩阵.
void mat_roi()
{
Mat m1(4,4,CV_8UC1);
Mat m2(4,4,CV_8UC3);
for (int i = 0;i < m1.rows;i++)
{
uchar* p = m1.ptr<uchar>(i);
for(int j = 0;j < m1.cols;j++)
{
p[j] = m1.cols * i + j;
}
}
for (int i = 0;i < m2.rows;i++)
{
Vec3b* p = m2.ptr<Vec3b>(i);
for (int j = 0;j < m2.cols;j++)
{
uchar pixel = m2.cols * i + j;
p[j][0] = pixel;
p[j][1] = pixel;
p[j][2] = pixel;
}
}
cout << "m1 = \n" << m1 << endl;
cout << "m2 = \n" << m2 << endl;
//取出矩阵的第 i 行(index = i - 1)
Mat line1 = m1.row(0);
Mat line2 = m2.row(0);
cout << "m1(0) = \n" << line1 << endl;
cout << "m2(0) = \n" << line2 << endl;
//取出矩阵的第 i 列(index = i - 1)
Mat col1 = m1.col(0);
Mat col2 = m2.col(0);
cout << "m1(0) = \n" << col1 << endl;
cout << "m2(0) = \n" << col2 << endl;
//取对角线
/*
* Mat Mat::diag(int d) const
参数 d=0 时,表示取主对角线;当参数 d>0 是,表示取主对角线下方的次对角线,
如 d=1 时,表示取主对角线下方,且紧贴主多角线的元素;当参数 d<0 时,表示取
主对角线上方的次对角线
*/
Mat diag1 = m1.diag(1);
Mat diag2 = m2.diag(0);
cout << "m1(diag) = \n" << diag1 << endl;
cout << "m2(diag) = \n" << diag2 << endl;
//多行、多列选中,用range(start,end)方法,注意包含start但不包含end,下标也是从0开始的
Mat A = Mat::eye(10,10,CV_8UC1);
Mat B = A(Range::all(),Range(1,3));//提取第 2 到 3 列 all()表示所有行或者列
Mat C = B(Range(5,9),Range(0,2)); //提取 B 的第 6 至 9 行
cout << "A = \n" << A << endl
<< "B = \n" << B << endl
<< "C = \n" << C << endl;
//roi方法
/*
Rect(int _x,int _y,int _width,int _height);
参数意思为:左上角x坐标
左上角y坐标
矩形的宽
矩形的高
//如果创建一个Rect对象rect(100, 50, 50, 100),那么rect会有以下几个功能:
rect.area(); //返回rect的面积 5000
rect.size(); //返回rect的尺寸 [50 × 100]
rect.tl(); //返回rect的左上顶点的坐标 [100, 50]
rect.br(); //返回rect的右下顶点的坐标 [150, 150]
rect.width(); //返回rect的宽度 50
rect.height(); //返回rect的高度 100
rect.contains(Point(x, y)); //返回布尔变量,判断rect是否包含Point(x, y)点
//还可以求两个矩形的交集和并集
rect = rect1 & rect2;
rect = rect1 | rect2;
//还可以对矩形进行平移和缩放
rect = rect + Point(-100, 100); //平移,也就是左上顶点的x坐标-100,y坐标+100
rect = rect + Size(-100, 100); //缩放,左上顶点不变,宽度-100,高度+100
//还可以对矩形进行对比,返回布尔变量
rect1 == rect2;
rect1 != rect2;
*/
Mat D = A(Rect(0,0,1,5));
Rect rect1(0,0,1,5);
Rect rect2(0,0,1,4);
cout << "D = \n" << D << endl
<< "rect = " << rect1 << endl;//rect1 = [1 x 5 from (0, 0)]
//使用括号运算符
Mat E = A(rect1);
cout << E << endl;
}
1.4.4 Mat 数学运算
void mat_calculate()
{
Mat A = Mat::eye(4,4,CV_32FC1);
Mat B = A * 3 + 1;
Mat C = B.diag(0) + B.col(1);
cout << "A = \n" << A << endl << endl;
cout << "B = \n" << B << endl << endl;
cout << "C = \n" << C << endl << endl;
// 对两个向量执行点乘运算,就是对这两个向量对应位一一相乘之后求和的操作,
//点乘的结果是一个标量。
cout << "C .* diag(B) = \n" << C.dot(B.diag(0)) << endl;
cout << C.mul(B.diag(0)) << endl;
cout << "A.t() = \n" << A.t() << endl;
//参与点乘的两个Mat矩阵的数据类型(type)只能是
//CV_32F、 CV_64FC1、 CV_32FC2、 CV_64FC2 这4种类型中的一种
cout << "A.inv() = \n" << A.inv() << endl;//取逆对type也有要求
cout << "A * B = \n" << A * B << endl;
//mul会计算两个Mat矩阵对应位的乘积,所以要求参与运算的矩阵A的行列和B的行列数一致。
//计算结果是跟A或B行列数一致的一个Mat矩阵。
cout << "A.mul(B) = \n" << A.mul(B) << endl;
//矩阵对应元素的乘法和除法: A.mul(B), A/B, alpha/A
//矩阵相乘
float left[2][3] = {
{1,2,3},{4,5,6}};
float right[3][2] = {
{1,4},{2,5},{3,6}};
Mat left_Mat(2,3,CV_32FC1,left);
Mat right_Mat(3,2,CV_32FC1,right);
Mat result_Mat = left_Mat * right_Mat;
cout << "left_Mat:\n" << left_Mat << endl
<< "right_Mat:\n" << right_Mat << endl
<< "result_Mat:\n" << result_Mat << endl;
}
A =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
B =
[4, 1, 1, 1;
1, 4, 1, 1;
1, 1, 4, 1;
1, 1, 1, 4]
C =
[5;
8;
5;
5]
C .* diag(B) =
92
[20;
32;
20;
20]
A.t() =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
A.inv() =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
A * B =
[4, 1, 1, 1;
1, 4, 1, 1;
1, 1, 4, 1;
1, 1, 1, 4]
A.mul(B) =
[4, 0, 0, 0;
0, 4, 0, 0;
0, 0, 4, 0;
0, 0, 0, 4]
left_Mat:
[1, 2, 3;
4, 5, 6]
right_Mat:
[1, 4;
2, 5;
3, 6]
result_Mat:
[14, 32;
32, 77]
1.4.5 Mat_类
待学习
貌似用在小型矩阵的直接输入
//小型矩阵 直接输入 使用Mat_()类
Mat small_mat = (Mat_<double>(3,3) << 0,-1,0,-1,5,6,1,4,7.1);
1.5 RNG类 随机数
RNG类是opencv里C++的随机数产生器。
它可产生一个64位的int随机数。
目前可按均匀分布和高斯分布产生随机数
void rng_test()
{
//创建RNG对象,使用默认种子“-1”
RNG rng;
//产生64位整数
int N1 = rng;
cout << "N1 = " << N1 << endl;
int N2 = rng.next(); //返回下一个随机整数,即N1.next();
cout << "N2 = " << N2 << endl;
/*-------------产生均匀分布的随机数uniform和高斯分布的随机数gaussian---------*/
//总是得到double类型数据0.000000,因为会调用uniform(int,int),只会取整数,所以只产生0
double N1a = rng.uniform(0,1);
cout << "N1a = " << N1a << endl;
//产生[0,1)范围内均匀分布的double类型数据
double N1b = rng.uniform((double)0,(double)1);
cout << "N1b = " << N1b << endl;
//产生[0,1)范围内均匀分布的float类型数据,注意被自动转换为double了。
double N1c = rng.uniform(0.f,1.f);
cout << "N1c = " << N1c << endl;
//产生[0,1)范围内均匀分布的double类型数据。
double N1d = rng.uniform(0.,1.);
cout << "N1d = " << N1d << endl;
double N2h = rng.operator double(); //返回下一个double型数
cout << "N2h = " << N2h << endl;
//可能会因为重载导致编译不通过(确实没通过。。)
//double N1e = rng.uniform(0,0.999999);
//产生符合均值为0,标准差为2的高斯分布的随机数
double N1g = rng.gaussian(2);
cout << "N1g = " << N1g << endl;
//=========================================================================//
//产生[1,1000)均匀分布的int随机数填充fillM
Mat_<int>fillM(3,3);
rng.fill(fillM,RNG::UNIFORM,1,1000);
cout << "filM = \n" << fillM << endl << endl;
Mat fillM1(3,3,CV_8UC1);
rng.fill(fillM1,RNG::UNIFORM,1,1000,true);
cout << "filM1 = \n" << fillM1 << endl << endl;
Mat fillM2(3,3,CV_8UC1);
rng.fill(fillM2,RNG::UNIFORM,1,1000,false);
cout << "filM2 = \n" << fillM2 << endl << endl;
//fillM1产生的数据都在[0,,255)内,且小于255;
//fillM2产生的数据虽然也在同样范围内,但是由于用了截断操作,所以很多数据都是255,
//产生均值为1,标准差为3的随机double数填进fillN
//Mat_<double>fillN(3,3);
Mat fillN(3,3,CV_64FC1);
rng.fill(fillN,RNG::NORMAL,1,3);
cout << "filN = \n" << fillN << endl << endl;
//====================================================================//
//randShuffle() 将原数组(矩阵)打乱
/*
randShuffle( InputOutputArray dst, 输入输出数组(一维)
double iterFactor=1. , 决定交换数值的行列的位置的一个系数...
RNG* rng=0 ) 可选)随机数产生器,0表示使用默认的随机数产生器,
即seed=-1。rng决定了打乱的方法
*/
Mat randShufM =(Mat_<double>(2,3) << 1,2,3,4,5,6);
cout << "randShufM = \n" << randShufM << endl;
randShuffle(randShufM,7,0);
cout << "randShufM = \n" << randShufM << endl;
}