OpenCV相关知识

OpenCV

1. Mat类

Mat类是OpenCV中十分重要的一个部分,OpenCV中的图像操作都要基于Mat类来进行,因此单独拿出一个小节来做关于Mat类的笔记。

Mat类构造函数

Mat类构造函数有很多,这里仅列出一些比较常用的。
关于构造函数中的参数详解,写在构造函数之后。
1、Mat::Mat()
无参数构造方法;

Mat img;//创建一个名为img的Mat类成员

2、Mat::Mat(int rows, int cols, int type)
创建行数为 rows,列数为 col,类型为 type 的图像;

Mat img(100,100,CV_8UC3);//创建一个100*100的图像,图像为三通道,数据为8位无符号整数

3、Mat::Mat(Size size, int type)
创建大小为 size,类型为 type 的图像;

Mat img(100,100,CV_8UC3);
Mat img2(img.size(),CV_8UC3);//创建一个大小与img相同的图像,图像为三通道,数据为8位无符号整数

4、Mat::Mat(int rows, int cols, int type, const Scalar& s)
创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s;

Mat img(100,100,CV_8UC3,Scalar(255,255,255));//创建一个100*100的图像,图像为三通道,数据为8位无符号整数,并将每个通道的值都置为255(也就是说这是一张全白的图片)

5、Mat::Mat(Size size, int type, const Scalar& s)
创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s;

Mat img(100,100,CV_8UC3);
Mat img2(img.size(),CV_8UC3,Scalar(255,255,255));//创建一个100*100的图像,图像为三通道,数据为8位无符号整数,并将每个通道的值都置为255(也就是说这是一张全白的图片)

Mat中的一些常见参数

参数 类型 描述
flags int Mat中的一些标记,一共32位,从低位到高位,包含了数据类型(0-2位)、通道数(3-11)等等,具体可以参考【OpenCV】从Mat的flags中可以读到的信息,以及相关宏定义
data uchar* 指向数据的指针
dims int 矩阵的维度
rows int 矩阵行数 维度大于2 则rows = -1
cols int 矩阵列数 维度大于2 则cols = -1
size MSize 数据内是一维数组,有个两元素,size[0]矩阵的行数,size[1]矩阵的列数
step MStep 数据内是一维数组,有个两元素,step[0]矩阵一行共多少字节,step[1]表示矩阵一个元素多少字节

type()
表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。例如 CV_8UC3表示8位无符号整形数据,通道数为3
数据类型共有以下几种

type中的表示法 数据类型
8U uchar
8S char
16U ushort
16S short
32S int
32F float
64F double

channels()
通道数,比如说一张RGB彩图,通道数为3,每个像素就由R、G、B三个通道组成
depth()
矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值,将type的预定义值去掉通道信息就是depth值,共有以下几种:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F

Mat类的赋值(深拷贝与浅拷贝)

将一个Mat A赋值给另一个Mat B,有四种方法

  1. 构造函数法    Mat A(B);
  2. 重载运算符法   A = B;
  3. 复制法     A.copyTo(B);
  4. 克隆法     B=A.clone();

方法1、2是浅拷贝(时间短,不安全),只拷贝矩阵头,不拷贝数据部分,A和B共用一块数据,A对元素的操作会影响B。
方法3、4是深拷贝(时间长,相对安全),拷贝矩阵的所有数据,包括矩阵头,最大的区别在于clone()会给目标矩阵重新分配新内存,而copyTo()不会,copyTo()只是修改目标矩阵内的元素的值与当前矩阵值相同

2.最常用的几个OpenCV操作

读取图片cv::imread()

函数原型:

Mat cv::imread(const String & filename, int flags = IMREAD_COLOR)

示例

Mat img = imread("lena.jpg",0);//以灰度图形式读取该图片
  • 返回值:Mat 类型,即返回读取的图像,读取图像失败时返回一个空的矩阵对象(Mat::data == NULL)
  • 参数1:filename, 读取的图片文件名,可以使用相对路径或者绝对路径,但必须带完整的文件扩展名(图片格式后缀)
  • 参数2: flags, 一个读取标记,用于选择读取图片的方式,默认值为1,即IMREAD_COLOR,flag值的设定与用什么颜色格式读取图片有关。
    flags值被被定义在enum cv::ImreadModes枚举类里面,也可以用数字来代表,常用的有:
    flags = -1:imread按原图读入图像 // = IMAGE_UNCHANGED
    flags = 0:imread按单通道的方式读入图像,即灰度图像 // = IMAGE_GRAYSCALE
    flags = 1:imread按三通道方式读入图像,即彩色图像 // = IMAGE_COLOR

创建窗口cv::namedWindow()

函数原型:

void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);

函数示例

namedWindow("ddd",WINDOW_NORMAL);

参数1:创建的窗口名
参数2:一个标记,默认为WINDOW_AUTOSIZE

  • WINDOW_AUTOSIZE 窗口大小自动适应图片大小,并且不可手动更改。
  • WINDOW_NORMAL 用户可以改变这个窗口大小
  • WINDOW_OPENGL 窗口创建的时候会支持OpenGL

显示图片cv::imshow()

函数原型

void imshow(const String& winname, InputArray mat);

函数示例

Mat img = imread("lena.jpg",0);
namedWindow("ddd",WINDOW_NORMAL);
imshow("ddd",img);

这个函数可以配合窗口创建函数namedWindow使用,实现将图片显示到指定的窗口中,只需要将第一个参数输入为创建的窗口名称即可

写入图片imwrite()

函数原型

bool imwrite( const String& filename, InputArray img,const std::vector<int>& params = std::vector<int>());

参数1:被写入的文件名,如果没有的话会自动创建
参数2:要写入的图片
参数3:表示为特定格式保存的参数编码(一般不用写,用默认的就可以)
函数示例

Mat img = imread("lena.jpg");
imwrite("dada.jpg",img);

3.像素操作

常用的访问图片中单个像素的方法有两种,一种是使用at函数;另一种是使用指针,即ptr函数;

at函数

cv::mat的成员函数: .at(int y, int x)可以用来存取图像中对应坐标为(x,y)的元素坐标。但是在使用它时要注意,在编译期必须要已知图像的数据类型,这是因为cv::mat可以存放任意数据类型的元素,并且at函数不会对数据进行任何强制类型转换。因此at方法的实现是用模板函数来实现的。假设提前已知一张图片img的数据类型为 unsigned char型灰度图(单通道),要对坐标为(14,25)的像素重新赋值为25,则对应操作如下:

img.at<uchar>(14,25) = 25;

假设要对一张多通道图片的某个像素进行操作,需要对每个通道单独进行操作,这个时候就要用到vector数组,比如Vec3b表示3元素的uchar类型的数组,具体操作如下:

img.at<Vec3b>(14,25) [0]= 25;//B通道
img.at< Vec3b >(14,25) [1]= 25;//G通道
img.at< Vec3b >(14,25 [2]= 25;//R通道

ptr指针

ptr指针可以让我们像使用平时在C中使用的指针一样来访问数据,具体用法如下

    cv::Mat image = cv::Mat(400, 600, CV_8UC1); 
    uchar * data01 = image.ptr<uchar>(0)[1];//定义一个指向第一行第二和元素的指针

4. 感兴趣区域(ROI)

有时我们对一张图片进行操作的时候,只想对它的一部分区域进行操作(比如说当我们想给图片添加一个水印,需要将一张小图片覆盖到一个大图片的一部分里),这个时候就需要设定一个感兴趣区域,此后的操作仅在这个区域进行。

原理

感兴趣区域是利用Mat类的浅拷贝来完成的,通过定义一个新的Mat类变量,将原图片的一部分以浅拷贝的方式赋值给新变量,这样新变量和原变量的图片数据信息是共用一块内存区域的,通过对新变量操作,就能改变原图片中的信息。

具体设置方法

有两种方法

  • 方法一:指定矩形坐标,并规定好长宽
Mat img = imread("lena.jpg");
Mat roi = img(Rect(100, 100, 200, 300));

Rect四个形参分别是:矩阵左上角点的x坐标,y坐标,长,高;

  • 方法二:指定矩形的行和列的范围(Range)
Mat img = imread("lena.jpg");
Mat roi = img(Range(100, 300), Range(200, 400));

猜你喜欢

转载自blog.csdn.net/dada19980122/article/details/111118385
今日推荐