opencv学习记录1


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;
}

猜你喜欢

转载自blog.csdn.net/qq_33993729/article/details/106723290
今日推荐