【OpenCV教程合集】一文入门和精通OpenCV
@TOC
1.数据类型
OpenCV所提供的矩阵的数据类型包含以下几种,在定义时输入枚举类型对应的关键字或者枚举类型对应的值均可:
CV_8U
占8位的unsigned
CV_8UC(n)
占8位的unsigned char
CV_8UC1
占8位的unsigned char 一通道
CV_8UC2
占8位的unsigned char 二通道
CV_8UC3
占8位的unsigned char 三通道
CV_8UC4
占8位的unsigned char 四通道
CV_8S
占8位的signed
CV_8SC(n)
占8位的signed char
CV_8SC1
占8位的signed char 一通道
CV_8SC2
占8位的signed char 二通道
CV_8SC3
占8位的signed char 三通道
CV_8SC4
占8位的signed char 四通道
CV_16U
占16位的unsigned
CV_16UC(n)
占16位的unsigned char
CV_16UC1
占16位的unsigned char 一通道
CV_16U2
占16位的unsigned char 二通道
CV_16U3
占16位的unsigned char 三通道
CV_16U4
占16位的unsigned char 四通道
CV_16S
占16位的signed
CV_16SC(n)
占16位的signed char
CV_16SC1
占16位的signed char 一通道
CV_16SC2
占16位的signed char 二通道
CV_16SC3
占16位的signed char 三通道
CV_16SC4
占16位的signed char 四通道
CV_16F
占16位的float
CV_16FC(n)
占16位的float char
CV_16FC1
占16位的float char 一通道
CV_16FC2
占16位的float char 二通道
CV_16FC3
占16位的float char 三通道
CV_16FC4
占16位的float char 四通道
CV_32S
占32位的signed
CV_32SC(n)
占32位的signed char
CV_32SC1
占32位的signed char 一通道
CV_32SC2
占32位的signed char 二通道
CV_32SC3
占32位的signed char 三通道
CV_32SC4
占32位的signed char 四通道
CV_32F
占32位的float
CV_32FC(n)
占32位的float char
CV_32FC1
占32位的float char 一通道
CV_32FC2
占32位的float char 二通道
CV_32FC3
占32位的float char 三通道
CV_32FC4
占32位的float char 四通道
CV_64F
占64位的float
CV_64FC(n)
占64位的float char
CV_64FC1
占64位的float char 一通道
CV_64FC2
占64位的float char 二通道
CV_64FC3
占64位的float char 三通道
CV_64FC4
占64位的float char 四通道
以下是各个枚举类型对应的值:
CV_8U
uchar
0
8
16
24
CV_8S
char
1
9
17
25
CV_16U
unsigned
2
10
18
26
CV_16S
signed
3
11
19
27
CV_32S
signed
4
12
20
28
CV_32F
float
5
13
21
29
CV_64F
float
6
14
22
30
2.矩阵基本操作
2.1 全零矩阵
参数如下
rows
行数
cols
列数
type
数据类型(CV_16F)
size
Size(宽(列数),高(行数))
Size与Mat中的成员函数.size()的返回值,有相同的数据类型,是[宽*高]。
Mat中的成员变量.size,与以上二者不同,是 rows*cols
2.2 全一矩阵
参数如下
rows
行数
cols
列数
type
数据类型(CV_16F)
size
Size(宽(列数),高(行数))
2.3 单位矩阵
参数如下
rows
行数
cols
列数
type
数据类型(CV_16F)
size
Size(宽(列数),高(行数))
2.4 矩阵转置
2.5 求逆矩阵
2.6 逗号式分隔创建矩阵
常用于自定义卷积核
以下为使用实例,注意括号的位置
注意 :给出的数据类型必须是基本数据类型,如int,double。不能是CV_16F等。
2.7 矩阵定义(只列出常用的)
参数如下
rows
行数
cols
列数
type
数据类型(CV_16F)
size
Size(宽(列数),高(行数))
2.7.1 数据类型Scalar
Scalar(gray)
Scalar(blue,green,red)
2.8 通过ptr与at函数遍历矩阵
2.8.1 Vec类型
以下为实例
用ptr访问可以不加Vec类型,ptr访问是最快的
用at访问必须加Vec类型,at访问比ptr略微慢一些
2.9 通过迭代器遍历矩阵(easy but very very slow)
3.图像基本操作
3.1 图片读取
3.2 创建窗口
参数如下
winname(window name)
窗体名
3.3 图片显示
参数如下
winname(window name)
窗体名
mat
输入的欲显示的图片
若窗体未创建,会自动进行创建
控制图片的展示时间,如设置delay=0,则表示一直展示,按SPACE停止展示
如设置delay不为0,则表示停留delay毫秒
3.4 图片保存
参数如下
filename
保存的文件名
img(image)
要保存的图片
3.5 视频输入输出
3.5.1 filename
影片档案名称(例如video.avi)
图片序列(例如img_%02d.jpg,将读取像这样的样本img_00.jpg, img_01.jpg, img_02.jpg, …)
视频流的网址(例如protocol://host:port/script_name?script_params|auth)。请注意,每个视频流或IP摄像机源均具有其自己的URL方案。请参考源流的文档以了解正确的URL。
3.5.2 index
要打开的视频捕获设备的ID。要使用默认后端打开默认摄像头,只需传递0。
当apiPreference为CAP_ANY时,使用camera_id + domain_offset(CAP_ *)向后兼容有效。
3.5.3 fourcc
用于编码视频文件的编码器,通过VideoWriter::fourcc函数获得
参数如下
VideoWriter::fourcc('M', 'P', '4', 'V')
MPEG-4编码,输出文件拓展名mp4
VideoWriter::fourcc( 'X' , '2' , '6' , '4' )
MPEG-4编码,输出文件拓展名mp4
VideoWriter::fourcc('P','I','M','1')
MPEG-1编码,输出文件拓展名avi
VideoWriter::fourcc('X','V','I','D')
MPEG-4编码,输出文件拓展名avi
VideoWriter::fourcc('I','4','2','0')
YUV编码,输出文件拓展名avi
VideoWriter::fourcc('T','H','E','O')
ogg vorbis编码,输出文件拓展名ogv
VideoWriter::fourcc('F',L','V','1')
flash video编码,输出文件拓展名flv
3.5.4 apiPreference(not important)
首选使用的Capture API后端。如果有多个可用的读取器实现,则可以用于实施特定的读取器实现。
设置读取的摄像头编号,默认CAP_ANY=0,自动检测摄像头。多个摄像头时,使用索引0,1,2,…进行编号调用摄像头。 apiPreference = -1时单独出现窗口,选取相应编号摄像头。
3.5.5 演示
3.6 通道分离与合并
3.6.1 分离
API(一)
参数如下
src(source)
输入图像
mvbegin(mat vector begin)
分离后的Mat数组的地址
API(二)
参数如下
m(mat)
输入图像
mv(mat vector)
分离后的的Mat数组,可以使用STL容器vector。
3.6.2 合并
API(一)
参数如下
mv(mat vector)
欲合并的图像数组的地址
count
欲合并的图像的个数
dst(destination)
输出图片
API(二)
参数如下
mv(mat vector)
欲合并的图像数组,可以使用STL容器vector。
dst(destination)
输出图片
3.7 图片色彩模式转换
3.7.1 API
参数如下
src(source)
源图像
dst(destination)
输出图片
code
转换码
3.7.2 转换类型和转换码
RGB和BGR(opencv默认的彩色图像的颜色空间是BGR)颜色空间的转换
cv::COLOR_BGR2RGB
cv::COLOR_RGB2BGR
cv::COLOR_RGBA2BGRA
cv::COLOR_BGRA2RGBA
向RGB和BGR图像中增添alpha通道
cv::COLOR_RGB2RGBA
cv::COLOR_BGR2BGRA
从RGB和BGR图像中去除alpha通道
cv::COLOR_RGBA2RGB
cv::COLOR_BGRA2BGR
从RBG和BGR颜色空间转换到灰度空间
cv::COLOR_RGB2GRAY
cv::COLOR_BGR2GRAY
cv::COLOR_RGBA2GRAY
cv::COLOR_BGRA2GRAY
从灰度空间转换到RGB和BGR颜色空间
cv::COLOR_GRAY2RGB
cv::COLOR_GRAY2BGR
cv::COLOR_GRAY2RGBA
cv::COLOR_GRAY2BGRA
RGB和BGR颜色空间与BGR565颜色空间之间的转换
cv::COLOR_RGB2BGR565
cv::COLOR_BGR2BGR565
cv::COLOR_BGR5652RGB
cv::COLOR_BGR5652BGR
cv::COLOR_RGBA2BGR565
cv::COLOR_BGRA2BGR565
cv::COLOR_BGR5652RGBA
cv::COLOR_BGR5652BGRA
灰度空间与BGR565之间的转换
cv::COLOR_GRAY2BGR555
cv::COLOR_BGR5552GRAY
RGB和BGR颜色空间与CIE XYZ之间的转换
cv::COLOR_RGB2XYZ
cv::COLOR_BGR2XYZ
cv::COLOR_XYZ2RGB
cv::COLOR_XYZ2BGR
RGB和BGR颜色空间与uma色度(YCrCb空间)之间的转换
cv::COLOR_RGB2YCrCb
cv::COLOR_BGR2YCrCb
cv::COLOR_YCrCb2RGB
cv::COLOR_YCrCb2BGR
RGB和BGR颜色空间与HSV颜色空间之间的相互转换
cv::COLOR_RGB2HSV
cv::COLOR_BGR2HSV
cv::COLOR_HSV2RGB
cv::COLOR_HSV2BGR
RGB和BGR颜色空间与HLS颜色空间之间的相互转换
cv::COLOR_RGB2HLS
cv::COLOR_BGR2HLS
cv::COLOR_HLS2RGB
cv::COLOR_HLS2BGR
RGB和BGR颜色空间与CIE Lab颜色空间之间的相互转换
cv::COLOR_RGB2Lab
cv::COLOR_BGR2Lab
cv::COLOR_Lab2RGB
cv::COLOR_Lab2BGR
RGB和BGR颜色空间与CIE Luv颜色空间之间的相互转换
cv::COLOR_RGB2Luv
cv::COLOR_BGR2Luv
cv::COLOR_Luv2RGB
cv::COLOR_Luv2BGR
Bayer格式(raw data)向RGB或BGR颜色空间的转换
cv::COLOR_BayerBG2RGB
cv::COLOR_BayerGB2RGB
cv::COLOR_BayerRG2RGB
cv::COLOR_BayerGR2RGB
cv::COLOR_BayerBG2BGR
cv::COLOR_BayerGB2BGR
cv::COLOR_BayerRG2BGR
cv::COLOR_BayerGR2BGR
3.8 改变图片的对比度和亮度
3.8.1 概述
a:控制对比度增益
b:控制亮度增益
3.8.2 手动(使用saturate_cast函数确保输出值不溢出范围)

3.8.3 API
参数如下
m(mat)
输出图片
rtype(result type)
输出图片的深度,-1表示与原图一致
alpha
对应系数
beta
对应常数
不能进行原地运算
3.8.4 效果

可以看到效果是一样的
3.9 图片混合
参数如下
src(source1)
输入图片1
alpha
src1的权重
src2(source2)
输入图片2
beta
src2的权重
gamma
额外的增量
dst(destination)
输出图片
dtype(destination type)
输出图片的数据类型,-1表示与输入图片一致
3.10 图片尺寸调整
参数如下
src(source)
输入图片
dsize(destination size)
输出图片的尺寸
fx
x方向(width方向)的缩放比例,如果它是0,那么它就会按照(double)dsize.width/src.cols来计算
fy
y方向(height方向)的缩放比例,如果它是0,那么它就会按照(double)dsize.height/src.rows来计算
interpolation
插值算法的选择
3.10.1 插值算法(not important)
3.10.2 注意事项
使用注意事项:
dsize和fx/fy不能同时为0
指定dsize的值,让fx和fy空置直接使用默认值。
让dsize为0,指定好fx和fy的值,比如fx=fy=0.5,那么就相当于把原图两个方向缩小一倍。
3.11 图像金字塔(常用于神经网络的池化层,对图像进行成倍的放大或缩小)
参数如下
src(source)
输入图片
dst(destination)
输出图片
dstsize(destination size)
输出图片的尺寸,默认自动调整
borderType
边界填充方式,默认为黑边。如果没有设置dstsize,则不会出现黑边,因为已经进行了自动调整
3.12 二值化(对灰度图)
参数如下
src(source)
输入图片
dst(destination)
输出图片
thresh(threshold)
阈值
maxval(max value)
最大值
type
阈值类型
3.12.1 阈值类型
阈值二值化(Threshold Binary)
首先指定像素的灰度值的阈值,遍历图像中像素值,如果像素的灰度值大于这个阈值,则将这个像素设置为最大像素值(8位灰度值最大为255);若像素的灰度值小于阈值,则将该像素点像素值赋值为0。公式以及示意图如下:

阈值反二值化(Threshold Binary Inverted)
首先也要指定一个阈值,不同的是在对图像进行阈值化操作时与阈值二值化相反,当像素的灰度值超过这个阈值的时候为该像素点赋值为0;当该像素的灰度值低于该阈值时赋值为最大值。公式及示意图如下:

截断(Truncate)
给定像素值阈值,在图像中像素的灰度值大于该阈值的像素点被设置为该阈值,而小于该阈值的像素值保持不变。公式以及示意图如下:

阈值取零(Threshold To Zero)
与截断阈值化相反,像素点的灰度值如果大于该阈值则像素值不变,如果像素点的灰度值小于该阈值,则该像素值设置为0.公式以及示意图如下:

阈值反取零(Threshold To Zero Inverted)
像素值大于阈值的像素赋值为0,而小于该阈值的像素值则保持不变,公式以及示意图如下:

3.13 图片裁剪
3.13.1 方式一
以下为实例
3.13.2 方式二
以下为实例

3.13.3 Rect类构造
3.14 基本变换
3.14.1 翻转
参数如下
src(source)
输入图片
dst(destination)
输出图片
flipCode
翻转类型,参见下表
flipCode 可选值如下
flipcode==0
上下翻转
flipcod>0
左右翻转
flipcode<0
上下加左右翻转,等价于旋转180°
效果

3.14.2 90°旋转
参数如下
src(source)
输入图片
dst(destination)
输出图片
rotateCode
旋转类型
效果

3.15 仿射变换
3.15.1 API
参数如下
src(source)
输入图片
dst(destination)
输出图片
M
变换矩阵
dsize(destination size)
输出图片的尺寸,若不对输出图片的尺寸进行调整,那么很可能会出现黑边
flags
插值算法
borderMode
边界外推法
borderValue
填充边界的值
3.15.2 平移
只需将变换矩阵M设置成如下形式:
delta_x:x方向上的偏移量
delta_y:y方向上的偏移量
M_values:必须是浮点类型的数组对象
M:必须是CV_32F,不能用逗号式分隔创建
效果

3.15.3 任意角度旋转
获得变换矩阵M
参数如下
center
旋转中心点的坐标
angle
逆时针偏角
scale
生成图与原图之比
效果

3.15.4 仿射(不破坏几何关系)
获得变换矩阵M
参数如下
src[](source[])
输入图片的坐标点集,含三个坐标点
dst[](destination[])
三个坐标点变换的目标位置
三个点要一一对应
3.16 透射变换(破坏几何关系)
3.16.1 API
进行变换
参数如下
src(source)
输入图片
dst(destination)
输出图片
M
变换矩阵
dsize(destination size)
输出图片的尺寸,若不对输出图片的尺寸进行调整,那么很可能会出现黑边
flags
插值算法
borderMode
边界外推法
borderValue
填充边界的值
已知变换后图片,逆推变换矩阵M
参数如下
src(source)
输入图片
dst(destination)
输出图片
获得变换矩阵M
参数如下
src[](source[])
输入图片的坐标点集,含四个坐标点
dst[](destination[])
三个坐标点变换的目标位置
四个点要一一对应
3.16.2 效果

4.滤波及边缘检测
4.1 均值滤波
4.1.1 卷积核形状
4.1.2 API
参数如下
src(source)
输入图片
dst(destination)
输出图片
ksize(kernal size)
卷积核宽高,必须是正奇数
anchor
滤波器中心像素位置,取(-1,-1)表示几何中心
borderType
边界填充方式,默认为黑边
4.1.3 效果

4.2 高斯滤波
4.2.1 卷积核形状
二维高斯函数表述为:
对应图形:

代码实现(不区分sigmaX与sigmaY)
4.2.2 API
参数如下
src(source)
输入图片
dst(destination)
输出图片
ksize(kernal size)
卷积核宽高。如果这个尺寸我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。
sigmaX
x方向上的标准差
sigmaY
y方向上的标准差。默认输入量为0,则将其设置为等于sigmaX,如果两个轴的标准差均为0,则根据输入的高斯滤波器尺寸计算标准偏差。
borderType
边界填充方式,默认为黑边
4.2.3 效果

4.3 中值滤波
4.3.1 原理
取滤波器内的中值作为输出,可以很好的抑制椒盐噪声
4.3.2 API
参数如下
src(source)
输入图片
dst(destination)
输出图片
ksize(kernal size)
卷积核边长,必须是正奇数
4.3.3 效果

4.4 高斯双边滤波
4.4.1 原理
双边滤波器的好处是可以做边缘保存(edge preserving),一般用高斯滤波去降噪,会较明显地模糊边缘,对于高频细节的保护效果并不明显。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。

4.4.2 API
参数如下
src(source)
输入图片
dst(destination)
输出图片
d
卷积核边长。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。
sigmaColor
颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
sigmaSpace
坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,卷积核大小已被指定且与sigmaSpace无关。否则,d正比于sigmaSpace。
borderType
边界填充方式,默认为黑边
4.4.3 效果

4.5 获取用来形态学操作的滤波器
shape:滤波器形状
ksize(kernal size):滤波器大小
anchor:滤波器中心像素位置,取(-1,-1)表示几何中心
4.6 腐蚀和膨胀(对二值图)
4.6.1 原理
腐蚀:取滤波器内的最小值作为输出
膨胀:取滤波器内的最大值作为输出
4.6.2 腐蚀API
参数如下
src(source)
输入图片,尽量是二值图
dst(destination)
输出图片
kernal
滤波器矩阵
anchor
滤波器中心像素位置,取(-1,-1)表示几何中心
iterations
执行erode函数的次数,默认执行一次
borderType
边界填充方式,默认为黑边
borderValue
填充边界的值
4.6.3 效果

4.6.4 膨胀API
参数如下
src(source)
输入图片,尽量是二值图
dst(destination)
输出图片
kernal
滤波器矩阵
anchor
滤波器中心像素位置,取(-1,-1)表示几何中心
iterations
执行erode函数的次数,默认执行一次
borderType
边界填充方式,默认为黑边
borderValue
填充边界的值
4.6.5 效果

4.7 形态学操作(对二值图)
4.7.1 API
参数如下
src(source)
输入图片,尽量是二值图
dst(destination)
输出图片
op(option)
变换类型
kernal
滤波器矩阵
anchor
滤波器中心像素位置,取(-1,-1)表示几何中心
iterations
执行erode函数的次数,默认执行一次
borderType
边界填充方式,默认为黑边
borderValue
填充边界的值
4.7.2 变换类型
4.7.3 开
原理
对输入图片先进行腐蚀,然后进行膨胀。可以用来屏蔽与滤波器大小相当的亮部。
效果

4.7.4 闭
原理
对输入图片先进行膨胀,然后进行腐蚀。可以用来屏蔽与滤波器大小相当的暗部。
效果

4.7.5 顶帽
原理
对输入图片先进行开操作,然后原图-开操作图。可以用来提取与滤波器大小相当的亮部。
效果

4.7.6 黑帽
原理
对输入图片先进行闭操作,然后闭操作图-原图。可以用来提取与滤波器大小相当的暗部。
效果

4.7.7 形态学梯度
原理
膨胀图与腐蚀图之差。可以用来 提取边界轮廓 ,但提取效果比不上专业的边缘检测算法。
效果

4.7.8 击中击不中变换
原理
击中击不中变换由下面三步构成:
用结构元素B1来腐蚀输入图像
用结构元素B2来腐蚀输入图像的补集
前两步结果的与运算
结构元素B1和B2可以结合为一个元素B。例如:

结构元素:左B1(击中元素),中B2(击不中元素),右B(两者结合)
本例中,我们寻找这样一种结构模式,中间像素属于背景,其上下左右属于前景,其余领域像素忽略不计(背景为黑色,前景为白色)。然后用上面的核在输入图像中找这种结构。从下面的输出图像中可以看到,输入图像中只有一个位置满足要求。

输入二值图像

输出二值图像
4.8 边缘检测:选择合适的输出深度
参照以下表格
CV_8U
CV_16S/CV_32F/CV_64F
CV_16U/CV_16S
CV_32F/CV_64F
CV_32F
CV_32F/CV_64F
CV_64F
CV_64F
4.8.1 normalize归一化函数
参数如下
src(source)
输入数组
dst(destination)
输出数组
alpha
如果norm_type为NORM_MINMAX ,则alpha为最小值或最大值;如果norm_type为其他类型,则为归一化要乘的系数
beta
如果norm_type为NORM_MINMAX ,则beta为最小值或最大值;如果norm_type为其他类型,beta被忽略.
norm_type
归一化类型,详见下面的内容
iterations
执行erode函数的次数,默认执行一次
dtype
输出数组的深度,若输入-1则表示与src一致。如果不能判断需要的深度,则可以输入-1然后使用convertScaleAbs绝对值化,这也是最推荐的做法,而不推荐自己判断深度。
mask
掩码,用于指示函数是否仅仅对指定的元素进行操作。大小必须与src保持一致。具体用法见8.1.4
归一化类型(只介绍常用的四种)
NORM_L1
NORM_L2
NORM_INF
NORM_MINMAX(recommended)
4.8.2 convertScaleAbs绝对值化
参数如下
src(source)
输入图片
dst(destination)
输出图片
4.9 sobel(对灰度图)
4.9.1 卷积核形状(ksize=3)
4.9.2 API
参数如下
src(source)
输入图片,数据类型Mat
dst(destination)
输出图片,数据类型Mat
ddepth(destination depth)
输出图片的深度(CV_16F)
dx
x方向导数的阶数,一般取1
dy
y方向导数的阶数,一般取1
ksize(kernal size)
卷积核边长,默认为3
scale
生成图与原图的缩放比例,默认为1
delta
额外的增量,默认为0
borderType
边界填充方式,默认为黑边
4.9.3 流程
用cvtColor函数转灰度图
在x,y方向上分别各调用一次Sobel
用convertScaleAbs函数转换到CV_8U,否则无法显示
用addWeighted函数把两张输出图片加在一起
4.9.4 同时在x,y方向上调用Sobel和分开调用的效果对比

可以看到效果差了很多
4.10 scharr(对灰度图)
4.10.1 卷积核形状(ksize恒定为3)
虽然Sobel算子可以有效的提取图像边缘,但是对图像中较弱的边缘提取效果较差。因此为了能够有效的提取出较弱的边缘,需要将像素值间的差距增大,因此引入Scharr算子。Scharr算子是对Sobel算子差异性的增强,因此两者之间的在检测图像边缘的原理和使用方式上相同。
4.10.2 API
参数如下
src(source)
输入图片,数据类型Mat
dst(destination)
输出图片,数据类型Mat
ddepth(destination depth)
输出图片的深度(CV_16F)
dx
x方向导数的阶数,一般取1
dy
y方向导数的阶数,一般取1
scale
生成图与原图的缩放比例,默认为1
delta
额外的增量,默认为0
borderType
边界填充方式,默认为黑边
4.10.3 流程
用cvtColor函数转灰度图
在x,y方向上分别各调用一次Scharr
用convertScaleAbs函数转换到CV_8U,否则无法显示
用addWeighted函数把两张输出图片加在一起
4.11 Laplacian(对灰度图)
4.11.1 卷积核形状(ksize=3)
Laplacian算子的卷积核形状决定了它 对噪声非常敏感 ,因此,通常需要通过 滤波平滑处理 。
4.11.2 API
参数如下
src(source)
输入图片,数据类型Mat
dst(destination)
输出图片,数据类型Mat
ddepth(destination depth)
输出图片的深度(CV_16F)
scale
生成图与原图的缩放比例,默认为1
delta
额外的增量,默认为0
borderType
边界填充方式,默认为黑边
4.11.3 流程
用中值滤波等操作平滑处理
用cvtColor函数转灰度图
用Laplacian函数处理
用convertScaleAbs函数转换到CV_8U,否则无法显示
4.12 Canny(recommended)
4.12.1 API
参数如下
image
输入图片,数据类型Mat
edges
输出图片,数据类型Mat
threshold1
最小阈值
threshold2
最大阈值
apertureSize
Sobel卷积核的大小,默认为3。核越大,对噪声越不敏感,但是边缘检测的错误也会随之增加
L2gradient
计算图像梯度幅度的标识,默认为false,表示L1范数(直接将两个方向的导数的绝对值相加)。如果使用true,表示L2范数(两个方向的导数的平方和再开方)
高于threshold2被认为是真边界,低于threshold1被抛弃,介于二者之间,则取决于是否与真边界相连。
4.12.2 流程
用中值滤波等操作平滑处理
用Canny函数处理 (不支持原地运算)
4.12.3 效果

4.13 添加噪声
为了检测算法的稳定性,常常需要在图片中人为地添加一些噪声来进行检验。
4.13.1 椒盐噪声
src(source):输入图片 dst(destination):输出图片 num(number):噪声的个数
4.13.2 高斯噪声
src(source):输入图片 dst(destination):输出图片 meanValue:高斯函数均值 std(standard deviation):高斯函数标准差
随机数填充矩阵
参数如下
mat
输入输出矩阵,最多支持4通道,超过4通道先用reshape()改变结构
distType(distination type)
可选UNIFORM 或 NORMAL,分别表示均匀分布和高斯分布
a
disType是UNIFORM,a表示下界(闭区间);disType是NORMAL,a表示均值
b
disType是UNIFORM,b表示上界(开区间);disType是NORMAL,b表示标准差
saturateRange
只针对均匀分布有效。当为真的时候,会先把产生随机数的范围变换到数据类型的范围,再产生随机数;如果为假,会先产生随机数,再进行截断到数据类型的有效区间。
5.画几何图形
5.1 直线
5.1.1 API
参数如下
img(image)
绘制多边形的画布,数据类型Mat
pt1(point1)
端点1
pt2(point2)
端点2
color
绘制线条的颜色
thickness
绘制线条的粗细
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
5.1.2 连通类型
LINE_4与LINE_8差别不大,而LINE_AA的抗锯齿效果显著
5.2 正矩形
5.2.1API
参数如下
img(image)
绘制多边形的画布,数据类型Mat
pt1(point1)
左上角端点
pt2(point2)
右下角端点
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
参数如下
img(image)
绘制多边形的画布,数据类型Mat
rec(rect)
一个矩形
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
5.3 圆形
5.3.1 API
参数如下
img(image)
绘制多边形的画布,数据类型Mat
center
圆心坐标
radius
半径
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
5.4 椭圆
5.4.1 API
参数如下
img(image)
绘制多边形的画布,数据类型Mat
center
圆心坐标
axes
(x方向上半轴长,y方向上半轴长)
angle
顺时针偏角
startAngle
以x方向上的正半轴为起点,偏移一定角度后的起点,从此起点开始画椭圆
endAngle
以x方向上的正半轴为起点,偏移一定角度后的终点,到此为止结束画椭圆
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
5.4.2 效果



5.5 斜矩形
5.5.1 API(通过RotatedRect类和line函数实现)
下面是自定义的一个快捷画斜矩形的函数
5.6 多边形
5.6.1 API
绘制方式一
参数如下
img(image)
绘制多边形的画布,数据类型Mat
pts(points)
多边形角点的坐标点集,数据类型vector<Point>或vector<vector<Point>>,若为vector<Point2f>或vector<vector<Point2f>>会报错
isClosed
多边形是否闭合,如果isClosed为真,那么pts的最后一个点将和第一个点连起来,否则轮廓被认为是不封闭的。
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
绘制方式二
参数如下
img(image)
绘制多边形的画布,数据类型Mat
pts(points)
多个多边形的角点坐标点集的地址的数组。如果有3个四边形的角点坐标点集Point[3][4],那么pts={Point[0][0],Point[1][0],Point[2][0],}
npts(number points)
多个多边形的角点坐标点集的元素个数排列成的数组,用来指示需要用到pts[i]中的几个元素。如果有3个四边形的角点坐标点集Point[3][4],那么npts={4,4,4,}
ncontours
多边形的数量
isClosed
多边形是否闭合,如果isClosed为真,那么pts的最后一个点将和第一个点连起来,否则轮廓被认为是不封闭的。
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
shift
坐标点小数点位数(not important)
6.Trackbar控件
6.1 createTrackbar创建滚动条
6.1.1 API
参数如下
trackbarname
滚动条名字
winname(window name)
窗体名字。要先用nameWindow创建好同名窗体,滚动条才会出现
value
欲控制的变量的地址
count
欲控制的变量的最大值(最小为0)
onChange
回调函数,默认为空。如果想要传入,那么其参数是固定的
userdata
万能指针,默认为空。如果想要传入,通常用一个类的对象的地址。作为可使用的数据库,用来给回调函数提供变量支持
6.2 getTrackbarPos获得滚动条当前的值
参数如下
trackbarname
滚动条名字
winname(window name)
窗体名字
6.3 使用方式一(recommended)
6.3.1 原理
不使用createTrackbar函数的参数value、onChange、userdata参数。通过while(1)的无限循环,在循环中不断地用getTrackbarPos函数动态地获取滚动条的值,然后在循环内部用这些值进行操作。
6.3.2 效果


6.4 使用方式二
6.4.1 原理
不使用getTrackbarPos函数,使用createTrackbar的全部参数,在onChange回调函数中完成所有操作,由于回调函数的参数表是固定的,因此**需要userdata传入所需数据。**在每次移动滚动条时,相当于调用了一次回调函数,就完成了操作。结尾没有waitKey(0)就显示不了多久。
6.4.2 效果


7.轮廓检测(一般对二值图)
7.1 查找轮廓
7.1.1 API
参数如下
image
输入图片,数据类型Mat
contours
保存输出轮廓的点坐标。通常用vector<vector<Point>>数据类型担任,通过Point可以看出存储的是坐标。
hierarchy
可选参数,保存输出轮廓的层级关系。通常用vector<Vec4i>数据类型担任。 详见下文
mode
轮廓层级的检测模式 ,详见下文
method
轮廓坐标点的储存方式 ,详见下文
offset
额外偏移量,在每一个检测出的轮廓点上加上该偏移量,可以是负值。当所分析图像是另外一个图像的ROI的时候,通过加减这个偏移量,可以把ROI图像的检测结果投影到原始图像对应位置上。
hierarchy[i][0]:第i个轮廓的同一层级后一个轮廓的索引编号。
hierarchy[i][1]:第i个轮廓的同一层级前一个轮廓的索引编号。
hierarchy[i][2]:第i个轮廓的子轮廓的索引编号。
hierarchy[i][3]:第i个轮廓的父轮廓的索引编号。
如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1。
7.1.2 轮廓层级检测模式:索引号(层级)
RETR_EXTERNAL(索引顺序:从右下到左上)
只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略

RETR_LIST(recommended)(索引顺序:从右下到左上,由外到内)
检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立层级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarch[i]向量内所有元素的第3、第4个分量都会被置为-1。

RETR_CCOMP(not recommended)(索引顺序:由内到外,从右下到左上)
检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层

RETR_TREE(recommended)
检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。

7.1.3 轮廓坐标点储存方式
method可选值如下
CHAIN_APPROX_NONE
保存物体边界上所有连续的轮廓点到contours向量内
CHAIN_APPROX_SIMPLE(recommended)
仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留,效率比较高。
CHAIN_APPROX_TC89_L1或CV_CHAIN_APPROX_TC89_KCOS
使用tehChinl chain 近似算法(not important)
7.2 绘制轮廓
7.2.1 API
参数如下
image
绘制轮廓的画布,数据类型Mat
contours
输入轮廓,数据类型vector<vector<Point>>
contourIdx(contour index)
欲绘制的轮廓的索引值,输入-1可以绘制所有轮廓
color
绘制线条的颜色
thickness
绘制线条的粗细。若取负值,则表示进行填充
lineType
绘制线条的连通类型
hierarchy
可选的层次结构信息。它仅在当你需要绘制一些轮廓线时被使用。(详见参数maxLevel)默认为noArray(),返回一个空数组。
maxLevel
绘制轮廓线的最高级别。此参数仅在参数hierarchy有效时被考虑。详见下表
offset
额外偏移量,在每一个绘制出的轮廓点上加上该偏移量,可以是负值。当所分析图像是另外一个图像的ROI的时候,通过加减这个偏移量,可以把ROI图像的绘制结果投影到原始图像对应位置上。
maxLevel可选值如下
0
只有被指定的轮廓被绘制
1
绘制被指定的轮廓和其下一级轮廓
2
绘制被指定的轮廓和其所有子轮廓
7.3 轮廓面积和周长
7.3.1 面积(非原地算法)
参数如下
contour
某一个轮廓,数据类型vector<Point>
oriented
有方向的区域标志(not important)。若为true: 此函数依赖轮廓的方向(顺时针或逆时针)返回一个已标记区域的值。若为false: 默认值,意味着返回不带方向的绝对值。
此函数利用格林公式计算轮廓的面积。对于具有自交点的轮廓,该函数几乎肯定会给出错误的结果。
7.3.2周长(非原地算法)
参数如下
curve
某一个轮廓,数据类型vector<Point>
closed
轮廓是否是闭合的
7.4 多边形逼近
参数如下
curve
某一个轮廓,数据类型vector<Point>
approxCurve
输出多边形的点集,数据类型vector<Point>
epsilon
设置精度,越小则精度越高,多边形越趋近于曲线,拟合效果更好但效率低。
closed
轮廓是否是闭合的
7.5 凸包
参数如下
points
输入点集,数据类型vector<Point>
hull
输出凸包。数据类型取决于returnPoints,vector<Point>或vector<int>
clockwise
拟合凸包的直线的转动方向,TRUE为顺时针,否则为逆时针。
returnPoints
若为true,则在hull中存储点的坐标。若为false,则在hull中存储点的索引,索引值根据参数points得到。默认为true
7.6 外接矩形
7.6.1最小外接矩形(返回RotatedRect)
参数如下
points
输入点集,数据类型vector<Point>
7.6.2最大外界矩形(返回Rect)
参数如下
points
输入点集,数据类型vector<Point>
8.特征工程
8.1 模板匹配
8.1.1 原理
模板图像在原图像上从原点开始移动,计算模板与原图被模板覆盖的地方的差别程度,计算方法有几种,然后将每次计算的结果放进输出矩阵。若原图像为A*B大小,模板为a*b大小,则 输出矩阵为(A-a+1)*(B-b+1) 大小。
8.1.2 API
参数如下
image
输入图像,数据类型Mat
templ(template)
模板图像,数据类型Mat
result
输出矩阵,深度为CV_32FC1。若原图像为A*B大小,模板为a*b大小,则 输出矩阵为(A-a+1)*(B-b+1) 大小。
method
模板匹配计算方法。详见下文
mask
掩码图像。其大小与模板图像必须相同,且必须为灰度图。匹配时,对于掩码中的非0像素匹配算法起作用,掩码中的灰度值为0的像素位置,匹配算法不起作用。
8.1.3 模板匹配计算方法
method可选值如下
TM_SQDIFF
计算平方误差,计算出来的值越小,则匹配得越好
TM_SQDIFF_NORMED
计算归一化平方误差,计算出来的值越接近0,则匹配得越好
TM_CCORR
计算相关性,计算出来的值越大,则匹配得越好
TM_CCORR_NORMED
计算归一化相关性,计算出来的值越接近1,则匹配得越好
TM_CCOEFF
计算相关系数,计算出来的值越大,则匹配得越好
TM_CCOEFF_NORMED
计算归一化相关系数,计算出来的值越接近1,则匹配得越好
8.1.4 掩码的使用
在进行特征匹配时,我们有时并不需要用整个图片作为模板,因为模板的背景可能会干扰匹配的结果。因此,我们需要加入掩码,就可以屏蔽掉背景进行模板匹配
获得掩码
模板图像转灰度图
二值化屏蔽背景
8.1.5 效果


8.1.5 模板匹配的缺陷
无法应对旋转

无法应对缩放

8.2 cornerHarris(对灰度图)
8.2.1 角点的描述
一阶导数(即灰度的梯度)的局部最大所对应的像素点;
两条及两条以上边缘的交点;
图像中梯度值和梯度方向的变化速率都很高的点;
角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。
8.2.2 原理(前置知识要求:线性代数)(bolcksize=2的情况)
使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。考虑到一个灰度图像,使用划动窗口(with displacements在x方向和y方向) 计算像素灰度变化。
其中:
w(x,y) is the window at position (x,y)
I(x,y) is the intensity at (x,y)
I(x+u,y+v) is the intensity at the moved window (x+u,y+v)、
为了寻找带角点的窗口,搜索像素灰度变化较大的窗口。于是, 我们期望最大化以下式子:
泰勒展开:
Ix,Iy是通过sobel算子计算的一阶导数
矩阵化:
得二次型:
因此有等式:
每个窗口中计算得到一个值。这个值决定了这个窗口中是否包含了角点。
其中,det(M) = 矩阵M的行列式,trace(M) = 矩阵M的迹
R为正值时,检测到的是角点,R为负时检测到的是边,R很小时检测到的是平坦区域。
8.2.3 API
参数如下
src(source)
输入图片**(灰度图)**,深度要求:CV_8UC1或CV_32FC1
dst(destination)
输出图片,数据类型Mat
bolckSize
检测窗口的大小,越大则对角点越敏感,一般取2
ksize(kernal size)
使用sobel算子计算一阶导数时的滤波器大小,一般取3即可。
k
计算用到的系数,公认一般取值在0.02~0.06。
borderType
边界填充方式,默认为黑边。
8.2.4 流程
转灰度图
使用cornerHarris函数检测
使用normalize函数归一化处理和convertScaleAbs绝对化
遍历输出图像并筛选角点。不要使用迭代器的遍历方式,因为太慢!
经过实测,以下这种用行数调用ptr函数的遍历方式是最快的

8.2.5 优点与缺点
测试代码
图片旋转,角点不变


图片缩放,角点改变


8.3 Shi-Tomasi(对灰度图)
8.3.1 原理
由于cornerHarris角点检的稳定性与k密切相关,而k是个经验值,难以设定最佳值,Shi-Tomasi在这一点上进行了改进
计算角点分数
8.3.2 API
参数如下
image
输入图片**(灰度图)**,深度要求:CV_8UC1或CV_32FC1
corners
输出角点的点集,数据类型vector<Point2f>
maxCorners
控制输出角点点集的上限个数,即控制corners.size()。输入0则表示不限制上限
qualityLevel
质量系数(小于1.0的正数,一般在0.01-0.1之间),表示可接受角点的最低质量水平。该系数乘以输入图像中最大的角点分数,作为可接受的最小分数;例如,如果输入图像中最大的角点分数值为1500且质量系数为0.01,那么所有角点分数小于15的角都将被忽略。
minDistance
角点之间的最小欧式距离,小于此距离的点将被忽略。
mask
掩码图像。其大小与输入图像必须相同,且必须为灰度图。计算时,对于掩码中的非0像素算法起作用,掩码中的灰度值为0的像素位置,算法不起作用。
blockSize
检测窗口的大小,越大则对角点越敏感。
useHarrisDetector
用于指定角点检测的方法,如果是true则使用Harris角点检测,false则使用Shi Tomasi算法。默认为False。
k
默认为0.04,只有useHarrisDetector参数为true时起作用。
8.3.3 流程
转灰度图
使用Shi-Tomasi函数检测
遍历角点集合即可
8.3.4 效果
Shi-Tomasi同样具有旋转不变性和尺度可变性



8.4 SIFT与SURF(对灰度图)
8.4.1 概述
cornerHarris和Shi-Tomasi都没能保证角点在尺度上的稳定性,因此SIFT和SURF针对这一特点进行了优化。由于其数学原理较为复杂,请自行查阅相关论文和文献,本文不再赘述。 相较于cornerHarris和Shi-Tomasi,SIFT和SURF的优点是显著的,其检测出的角点对旋转、尺度缩放、亮度变化等保持不变性,对视角变换、仿射变化、噪声也保持一定程度的稳定性,是一种非常优秀的局部特征描述算法。 需要注意的是,SIFT和SURF的计算量较为庞大,难以做到实时运算。SIFT和SURF两者相比,SIFT更为精确,SURF更为高效。
8.4.2 API
构造函数
构造函数的参数设计复杂的数学原理,在此不进行解释,在使用时进行默认的构造即可。
关键点检测
参数如下
image
输入图像**(灰度图)**,深度要求:CV_8UC1或CV_32FC1
keypoints
含多个关键点的vector<KeyPoint>。使用detect时作为输出,使用compute时作为输入,使用detectAndCompute时可以作为输入也可以作为输出。
mask
掩码图像。其大小与输入图像必须相同,且必须为灰度图。计算时,对于掩码中的非0像素算法起作用,掩码中的灰度值为0的像素位置,算法不起作用。
描述子计算
参数如下
image
输入图片**(灰度图)**,深度要求:CV_8UC1或CV_32FC1
keypoints
含多个关键点的vector<KeyPoint>。使用detect时作为输出,使用compute时作为输入,使用detectAndCompute时可以作为输入也可以作为输出。
descriptors
描述子,数据类型Mat。在进行特征匹配的时候会用到。
useProvidedKeypoints
false时,keypoints作为输出,并根据keypoints算出descriptors。true时,keypoints作为输入,不再进行detect,即不修改keypoints,并根据keypoints算出descriptors。
drawKeypoints绘制关键点
参数如下
image
输入图像,数据类型Mat
keypoints
含多个关键点的vector<KeyPoint>
outImage
输出图像,数据类型Mat
color
绘制颜色信息,默认绘制的是随机彩色。
flags
特征点的绘制模式,其实就是设置特征点的那些信息需要绘制,那些不需要绘制。详见下表
flags可选值如下
DrawMatchesFlags::DEFAULT
只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标。
DrawMatchesFlags::DRAW_OVER_OUTIMG
函数不创建输出的图像,而是直接在输出图像变量空间绘制,要求本身输出图像变量就是一个初始化好了的,size与type都是已经初始化好的变量。
DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS
单点的特征点不被绘制
DrawMatchesFlags::DRAW_RICH_KEYPOINTS
绘制特征点的时候绘制的是一个个带有方向的圆,这种方法同时显示图像的坐标,size和方向,是最能显示特征的一种绘制方式。
8.4.3 流程
实例化SIFT或SURF对象
将输入图像转灰度图
根据需要,调用detect函数或compute函数或detectAndCompute函数,检测关键点和计算描述子
调用drawKeypoints函数绘制关键点
8.4.4 效果

进行缩放和旋转


可以看到,无论是旋转还是缩放,关键点都保持得非常稳定。
8.5 FAST到OBR(对灰度图)
8.5.1 概述
前文已经阐述,SIFT和SURF已经做到了角点在旋转和缩放下的稳定性,但是它们还有一个致命的缺陷,就是它们难以做到实时运算,因此,FAST和OBR应运而生了。
FAST原理
从图片中选取一个坐标点P,获取该点的像素值,接下来判定该点是否为特征点. 选取一个以选取点P坐标为圆心的半径等于r的Bresenham圆(一个计算圆的轨迹的离散算法,得到整数级的圆的轨迹点),一般来说,这个圆上有16个点,如下所示

p在图像中表示一个被识别为兴趣点的像素。令它的强度为 Ip;
选择一个合适的阈值t;
考虑被测像素周围的16个像素的圆圈。 如果这16个像素中存在一组ñ个连续的像素的像素值,比 Ip+t 大,或比 Ip−t小,则像素p是一个角点。ñ被设置为12。
使用一种快速测试(high-speed test)可快速排除了大量的非角点。这个方法只检测在1、9、5、13个四个位置的像素,(首先检测1、9位置的像素与阈值比是否太亮或太暗,如果是,则检查5、13)。如果p是一个角点,则至少有3个像素比 Ip+t大或比 Ip−t暗。如果这两者都不是这样的话,那么p就不能成为一个角点。然后可以通过检查圆中的所有像素,将全部分段测试标准应用于通过的对候选的角点。这种探测器本身表现出很高的性能,但有一些缺点:
它不能拒绝n <12的候选角点。当n<12时可能会有较多的候选角点出现
检测到的角点不是最优的,因为它的效率取决于问题的排序和角点的分布。
角点分析的结果被扔掉了。过度依赖于阈值
多个特征点容易挤到一起。
前三点是用机器学习方法解决的。最后一个是使用非极大值抑制来解决。具体不再展开。
FAST算法虽然很快,但是没有建立关键点的描述子,也就无法进行特征匹配
OBR简介
ORB 是 Oriented Fast and Rotated Brief 的简称,从这个简介就可以看出,OBR算法是基础FAST算法的改进。其中,Fast 和 Brief 分别是特征检测算法和向量创建算法。ORB 首先会从图像中查找特殊区域,称为关键点。关键点即图像中突出的小区域,比如角点,比如它们具有像素值急剧的从浅色变为深色的特征。然后 ORB 会为每个关键点计算相应的特征向量。ORB 算法创建的特征向量只包含 1 和 0,称为二元特征向量。1 和 0 的顺序会根据特定关键点和其周围的像素区域而变化。该向量表示关键点周围的强度模式,因此多个特征向量可以用来识别更大的区域,甚至图像中的特定对象。 关于Brief算法的具体原理本文不再赘述,请自行查阅相关论文和文献。
8.5.2 API
构造函数
threshold:进行FAST检测时用到的阈值,阈值越大检测到的角点越少
8.5.3 流程
实例化FAST或OBR对象
将输入图像转灰度图
根据需要,调用detect函数或compute函数或detectAndCompute函数,检测关键点和计算描述子
调用drawKeypoints函数绘制关键点
8.5.4 效果
调整threshold


进行缩放和旋转

错误
前文已经提及,FAST算法不支持描述子的计算
8.6 Brute-Force与FLANN特征匹配
8.6.1 概述
Brute-Force
暴力匹配(Brute-force matcher)是最简单的二维特征点匹配方法。对于从两幅图像中提取的两个特征描述符集合,对第一个集合中的每个描述符Ri,从第二个集合中找出与其距离最小的描述符Sj作为匹配点。 暴力匹配显然会导致大量错误的匹配结果,还会出现一配多的情况。通过交叉匹配或设置比较阈值筛选匹配结果的方法可以改进暴力匹配的质量。
如果参考图像中的描述符Ri与检测图像中的描述符Sj的互为最佳匹配,则称(Ri , Sj)为一致配对。交叉匹配通过删除非一致配对来筛选匹配结果,可以避免出现一配多的错误。
比较阈值筛选是指对于参考图像的描述符Ri,从检测图像中找到距离最小的描述符Sj1和距离次小的描述符Sj2。设置比较阈值t∈[0.5 , 0.9],只有当最优匹配距离与次优匹配距离满足阈值条件d (Ri , Sj1) ⁄ d (Ri , Sj2) < t时,表明匹配描述符Sj1具有显著性,才接受匹配结果(Ri , Sj1)。
FLANN
相比于Brute-Force,FLANN的速度更快
由于使用的是邻近近似值,所以精度较差
8.6.2 API
构造函数
参数如下
normType
计算距离用到的方法,默认是欧氏距离。详见下表
crossCheck
是否使用交叉验证,默认不使用。
normType可选值如下
NORM_L1
L1范数,曼哈顿距离
NORM_L2
L2范数,欧氏距离
NORM_HAMMING
汉明距离
NORM_HAMMING2
汉明距离2,对每2个比特相加处理。
NORM_L1、NORM_L2适用于SIFT和SURF检测算法
NORM_HAMMING、NORM_HAMMING2适用于OBR算法
描述子匹配
匹配方式一
参数如下
queryDescriptors
描述子的查询点集,数据类型Mat,即参考图像的特征描述符的集合。
trainDescriptors
描述子的训练点集,数据类型Mat,即检测图像的特征描述符的集合。
matches
匹配结果,长度为成功匹配的数量。
mask
掩码图像。其大小与输入图像必须相同,且必须为灰度图。计算时,对于掩码中的非0像素算法起作用,掩码中的灰度值为0的像素位置,算法不起作用。
特别注意和区分哪个是查询集,哪个是训练集
匹配方式二
参数如下
queryDescriptors
描述子的查询点集,数据类型Mat,即参考图像的特征描述符的集合。
trainDescriptors
描述子的训练点集,数据类型Mat,即检测图像的特征描述符的集合。
matches
vector<std::vector<DMatch>>类型,对每个特征点返回k个最优的匹配结果
k
返回匹配点的数量
mask
掩码图像。其大小与输入图像必须相同,且必须为灰度图。计算时,对于掩码中的非0像素算法起作用,掩码中的灰度值为0的像素位置,算法不起作用。
特别注意和区分哪个是查询集,哪个是训练集
Brute-Force与FLANN对输入描述子的要求
Brute-Force要求输入的描述子必须是CV_8U或者CV_32S
FLANN要求输入的描述子必须是CV_32F
drawMatches绘制匹配结果
参数如下
img1(image1)
源图像1,数据类型Mat
keypoints1
源图像1的关键点
img2(image2)
源图像2,数据类型Mat
keypoints2
源图像2的关键点
matches1to2
源图像1的描述子匹配源图像2的描述子的匹配结果
outImg(out image)
输出图像,数据类型Mat
matchColor
匹配的颜色(特征点和连线),默认Scalar::all(-1),颜色随机
singlePointColor
单个点的颜色,即未配对的特征点,默认Scalar::all(-1),颜色随机
matchesMask
掩码,决定哪些点将被画出,若为空,则画出所有匹配点
flags
特征点的绘制模式,其实就是设置特征点的那些信息需要绘制,那些不需要绘制。
8.6.3 流程
实例化BFMatcher对象
根据需要,调用match函数或knnMatch函数,进行特征匹配
调用drawMatches函数呈现原图,并且绘制匹配点
8.6.4 效果
不进行比率筛选


进行比率筛选




8.7 单应性矩阵
8.7.1 概述
使用最小均方误差或者RANSAC方法,计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列),配合perspectivetransform函数,

8.7.2 API
findHomography
参数如下
srcPoints
源平面中点的坐标矩阵,可以是CV_32FC2类型,也可以是vector<Point2f>类型
dstPoints
目标平面中点的坐标矩阵,可以是CV_32FC2类型,也可以是vector<Point2f>类型
method
计算单应矩阵所使用的方法。不同的方法对应不同的参数,参考如下表格。
ransacReprojThreshold
将点对视为内点的最大允许重投影错误阈值(仅用于RANSAC和RHO方法)。若srcPoints和dstPoints是以vector<Point2f>为单位的,则该参数通常设置在1到10的范围内,建议选择5
mask
可选输出掩码矩阵。通常由鲁棒算法(RANSAC或LMEDS)设置。 请注意,输入掩码矩阵是不需要设置的。
maxIters
RANSAC算法的最大迭代次数,默认值为2000
confidence
可信度值,取值范围为0到1
method可选值如下
0
利用所有点的常规方法
RANSAC
基于RANSAC的鲁棒算法
LMEDS
最小中值鲁棒算法
RHO
基于PROSAC的鲁棒算法
perspectivetransform
perspectivetransform函数与warpPerspective函数的区别在于:
perspectivetransform是对vector<Point2f>进行变换
warpPerspective是对Mat进行变换
8.7.2 流程
通过特征检测算法检测关键点和计算描述子
通过特征匹配算法得到匹配结果
对匹配结果进行遍历,用DMatch.queryIdx成员变量和DMatch.trainIdx成员变量,分别对查询的关键点集合和训练的关键点集合进行索引,并用KeyPoint.pt成员变量得到其坐标,这样就得到了两个vector<Point2f>
调用findHomography函数获得单应性矩阵
调用perspectivetransform函数对查询图的四角对应坐标点集vector<Point2f>进行变换,就得到了我们想要查找的图片在训练图中的四角对应坐标点集vector<Point2f>
用polylines函数在训练图中画出结果
8.7.3 效果

9.结语与感谢
对于所有看到这儿的朋友们,我很高兴地祝贺你们已经完成了OpenCV的基础知识学习,我可以很明确地说,你们对计算机视觉领域的了解已经超过了绝大多数的人,恭喜你们。本文总计八万二千一百五十三字,三千六百一十二行,是本人第一次撰写的长篇系列教程,多有不当之处,谢谢读者们对我的包容和支持。 然而,纸上得来终觉浅,绝知此事要躬行。本文只是基础知识的讲解,关于OpenCV的实战项目,敬请关注本人的后续文章。 以上。
最后更新于
这有帮助吗?