ubuntu+opencv+vscode+cmakelists:

1.下载opencv4压缩包:https://opencv.org/releases/的.zip文件
2.生成opencv4文件:解压完发现opencv是一个cmake工程,里面有CMakeList.txt,因此需要cmake生成Makefile。建一个build文件夹并进去使用cmake ..,而后使用make或者make -j4,make -j8 , make -12,来编译,j后面这个数字时调用多线程进行编译。此时opencv便被安装到了/usr/local/include/opencv4,对应库文件的路径则为/usr/local/lib。此时opencv4便被安装好了,使用pkg-config opencv —modversion可以检验是否安装成功。
3.配置vscode:
需要修改c_cpp_properties.json,tasks.json和launch.json
1>按下ctrl+shift+p搜索Edit Configuration进入编辑配置(JSON),在includePath中新增opencv4的路径/usr/local/include/opencv4
2>ctrl+shift+p搜索Tasks:Configure Task后选择用g++编译,修改tasks.json为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ build active file", /* 与launch.json文件里的preLaunchTask的内容保持一致 */
"command": "/usr/bin/g++",
"args": [
"-std=c++11",
"-g",
//"${file}", /* 编译单个文件 */
"${fileDirname}/*.cpp", /* 编译多个文件 */
"-o",
"${fileDirname}/${fileBasenameNoExtension}", /* 输出文件路径 */

/* 项目所需的头文件路径 */
"-I","${workspaceFolder}/",
"-I","/usr/local/include/",
"-I","/usr/local/include/opencv4/",
"-I","/usr/local/include/opencv4/opencv2",

/* 项目所需的库文件路径 */
"-L", "/usr/local/lib",

/* OpenCV的lib库 */
"/usr/local/lib/libopencv_*",

],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}

2>
3>按下ctrl+shift+D后点击创建项目的launch.json文件,修改为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"version": "0.2.0",
"configurations": [
{
"name": "g++ - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}", //程序文件路径
"args": [], //程序运行需传入的参数
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": true, //运行时是否显示控制台窗口
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++ build active file",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}

4.编写CMakeLists.txt文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 2.8)
project(test)

# 查找OpenCV包
find_package(OpenCV REQUIRED)

# 包含OpenCV头文件目录
include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(TEST src/test.cpp)

# 将OpenCV库链接到目标
target_link_libraries(TEST ${OpenCV_LIBS})

5.至此,完成配置
在ubuntu中启用与禁用anaconda:
sudo gedit ~/.bashrc打开.bashrc文件
启用则写入:export PATH=~/anaconda3/bin:$PATH
要实现bash环境的自动启动写入:source ~/anaconda3/bin/activate
否则需要在终端中键入source activate才能进入
禁用则把上述两行代码注释掉即可
最后记得source ~/.bashrc刷新文件

常用的anaconda命令:

查询虚拟环境:conda env list
创建虚拟环境:conda create -n name python=3.xx
删除虚拟环境:conda remove -n name —all
进入虚拟环境:conda activate name
退出虚拟环境:conda deactivate

基础知识:

二值图像:
一幅二值图像的二维矩阵仅由0、1两个值构成,“0”代表黑色,“1”代表白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。
灰度图:
每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;但是,灰度图像在黑色与白色之间还有许多级的颜色深度。灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,用于显示的灰度图像通常用每个采样像素8位的非线性尺度来保存,这样可以有256级灰度(如果用16位,则有65536级)。
彩色图:
每个像素通常是由红(R)、绿(G)、蓝(B)三个分量来表示的,分量介于(0,255)。RGB图像与索引图像一样都可以用来表示彩色图像。与索引图像一样,它分别用红(R)、绿(G)、蓝(B)三原色的组合来表示每个像素的颜色。但与索引图像不同的是,RGB图像每一个像素的颜色值(由RGB三原色表示)直接存放在图像矩阵中,由于每一像素的颜色需由R、G、B三个分量来表示,M、N分别表示图像的行列数,三个M x N的二维矩阵分别表示各个像素的R、G、B三个颜色分量。RGB图像的数据类型一般为8位无符号整形,通常用于表示和存放真彩色图像。

一、图像IO操作

1.读取图像:cv.imread(filename,flags)
参数:filename:要读取的图像及其路径
flags:读取方式
cv.IMREAD_COLOR:彩色模式,忽略透明度(默认参数)
cv.IMREAD_GRAYSCALE:灰度模式
cv.IMREAD_UNCHANGED:彩色模式,考虑透明度
返回值:图片名,numpy类型用于存储图片
2.显示图像:cv.imshow(winname,mat)
参数:winname:显示图像的窗口名称,以字符串类型表示
mat:要加载的图像
返回值:无
在调用显示图像的API后,要调用cv.waitKey()给图像绘制留下时间。
3.保存图像:cv.imwrite(filename,img)
参数:filename:保存的文件名机器路径
img:要保存的图片名
返回值:无

二、绘制几何图形:

1.绘制直线:cv.line(img,start,end,color,thickness)
参数:img:要绘制直线的图像
Start,end: 直线的起点和终点
color: 线条的颜色
Thickness: 线条宽度
返回值:无
2.绘制圆形:cv.circle(img,centerpoint, r, color, thickness)
参数:img:要绘制圆形的图像
Centerpoint, r: 圆心和半径
color: 线条的颜色
Thickness: 线条宽度,为-1时生成闭合图案并填充颜色
返回值:无
3.绘制矩形:cv.rectangle(img,leftupper,rightdown,color,thickness)
参数:img:要绘制矩形的图像
Leftupper, rightdown: 矩形的左上角和右下角坐标
color: 线条的颜色
Thickness: 线条宽度
返回值:无
4.添加文字:cv.putText(img,text,station, font, fontsize,color,thickness,lineType)
参数:img: 图像
text:要写入的文本数据
station:文本的放置位置
font:字体
Fontsize :字体大小
color:颜色
Thickness: 线条宽度
lineType:线渲染,值越大边缘越光滑,例如cv.LINE_8和cv.LINE_AA

三、获取并修改图像中的像素点

我们可以通过行和列的坐标值获取该像素点的像素值。对于BGR图像,它返回一个蓝,绿,红值的数组。对于灰度图像,仅返回相应的强度值。使用相同的方法对像素值进行修改。
px = img[100,100] # 获取某个像素点的值
blue = img[100,100,0] # 仅获取蓝色通道的强度值
img[100,100] = [255,255,255] # 修改某个位置的像素值

四、获取图像的属性:

图像属性包括行数,列数和通道数,图像数据类型,像素数等。对应的API如下所示:
其中shape返回元组(高度,宽度,通道数),size返回高度宽度通道数

五、图像通道的拆分与合并

有时需要在B,G,R通道图像上单独工作。在这种情况下,需要将BGR图像分割为单个通道。或者在其他情况下,可能需要将这些单独的通道合并到BGR图像。
b,g,r = cv.split(img) # 通道拆分
img = cv.merge((b,g,r)) # 通道合并

六、色彩空间的转变:cv.cvtColor(img,code)

参数:img: 进行颜色空间转换的图像
code: 转换类型
cv.COLOR_BGR2GRAY : BGR转Gray
cv.COLOR_BGR2HSV: BGR转HSV

七、图像的四则运算与混合操作:

OpenCV的四则运算是饱和操作,即存在对应的上下限,例如在RGB图中只可能于[0,255]
dst=cv.add(x,y) #图像的加法
dst=cv.addWeighted(img1,α,img2,β,γ) #dst = α⋅img1 + β⋅img2 + γ

八、几何变换:

1.图像缩放:cv2.resize(src,dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)
参数:src : 输入图像
dsize: 绝对尺寸,直接指定调整后图像的大小
fx,fy: 相对尺寸,将dsize设置为None,然后将fx和fy设置为比例因子即可
interpolation:插值方法

2.图像旋转(仿射变换的一部分):cv.warpAffine(img,M,dsize)
参数:img: 输入图像
M:2∗3移动矩阵,通过cv.getRotationMatrix2D(center, angle, scale)求解
center:旋转中心
angle:旋转角度
scale:缩放比例
dsize: 输出图像的大小
3.图像平移(仿射变换的一部分):cv.warpAffine(img,M,dsize)
参数:img: 输入图像
M:2∗3移动矩阵,np.float32([[1,0,tx],[0,1,ty]])
dsize: 输出图像的大小
4.仿射变换:cv.warpAffine(img,M,dsize)
图像的仿射变换涉及到图像的形状位置角度的变化,是深度学习预处理中常到的功能,仿射变换主要是对图像的缩放,旋转,翻转和平移等操作的组合。
以下图为例解释图像的仿射变换,图1中的点1, 2 和 3 与图二中三个点一一映射, 仍然形成三角形, 但形状已经大大改变,通过这样两组三点(感兴趣点)就可以得到一组仿射变换,把这个仿射变换应用到图像中所有的点中,就完成了图像的仿射变换。

参数:img: 输入图像
M:2∗3移动矩阵,通过cv.getAffineTransform(pts1,pts2)求解,其中pts1和 pts2分别是仿射前后三个点的位置,用np.float32([[x,y,z],[x’,y’,z’]])表示
dsize: 输出图像的大小
5.透射变换:cv.warpPerspective(img,T,dsize)
透射变换是视角变化的结果,是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。

参数:img: 输入图像
T:3∗3透视变换矩阵,通过cv.getPerspectiveTransform(pts1,pts2)求解, 其中pts1和pts2分别是透射前后四个点的位置(任意三个不共线),
用np.float32([[x,y,z,a],[x’,y’,z’,a’]])表示
dsize: 输出图像的大小
6.图像金字塔:cv.pyrUp/Down(img) #上采样/下采样
图像金字塔是图像多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。图像金字塔用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似,层级越高,图像越小,分辨率越低。

九、形态学操作:

1.腐蚀:cv.erode(img,kernel,iterations)
腐蚀使原图中的高亮区域被蚕食,效果图有比原图更小的高亮区域,是求局部最小值的操作。
腐蚀的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点。
具体操作是:用一个核结构扫描图像中的每一个像素,用图中的每一个与核结构相同大小的像素块与核结构像素做“与”操作,如果都为1,则该像素块的中心点为1,否则为0。如下图所示,结构A被核结构B腐蚀后:(图有误,点(2,3)应为白色)

参数:img: 要处理的图像
kernel: 核结构
iterations: 腐蚀的次数,默认是1
2.膨胀: cv.dilate(img,kernel,iterations)
膨胀使图像中高亮部分扩张,效果图拥有比原图更大的高亮区域,是求局部最大值的操作。
膨胀的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的孔洞。
具体操作是:用一个核结构扫描图像中的每一个像素,用图中的每一个与核结构相同大小的像素块与核结构像素做“或”操作,如果都为0,则该像素块的中心点为0,否则为1。如下图所示,结构A被核结构B膨胀后:

参数的意义和腐蚀一样,在此不再赘述。

3.开运算和闭运算:cv.morphologyEx(img, op, kernel)
开运算是先腐蚀后膨胀,其作用是分离物体,消除小区域;其特点是消除噪点,去除小的干扰块,而不影响原来的图像。闭运算则与开运算相反,是先膨胀后腐蚀,作用是消除闭合物体里面的孔洞,特点是可以填充闭合区域。

参数:img: 要处理的图像
op: 若进行开运算,则设为cv.MORPH_OPEN
若进行闭运算,则设为cv.MORPH_CLOSE
Kernel: 核结构
4.礼帽与黑帽运算:cv.morphologyEx(img, op, kernel)
礼帽运算是原图像与开运算的结果图之差,黑帽运算是原图像与闭运算的结果图之差。
因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,故礼帽运算用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用礼帽运算进行背景提取。而黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,故黑帽运算用来分离比邻近点暗一些的斑块。
参数:img: 要处理的图像
op: 若进行礼帽运算,则设为cv.MORPH_TOPHAT
若进行黑帽运算,则设为cv.MORPH_BLACKHAT
Kernel: 核结构
最后来看一些示例:

十、图像噪声

1.椒盐噪声:cv.addSaltAndPepperNoise(img, noise_den, noise_val)
椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。椒盐噪声的成因可能是影像讯号受到突如其来的强烈干扰而产生、类比数位转换器或位元传输错误等。例如失效的感应器导致像素值为最小值,饱和的感应器导致像素值为最大值。

参数:img:源图像
noise_den:噪声密度(噪声像素占总像素的比例)
noise_val:噪声强度(噪声像素值,可以是0或255)。
2.高斯噪声:
高斯噪声是指噪声密度函数服从高斯分布的一类噪声。由于高斯噪声在空间和频域中数学上的易处理性,这种噪声(也称为正态噪声)模型经常被用于实践中。高斯随机变量z的概率密度函数由下式给出:

其中z表示灰度值,μ表示z的平均值或期望值,σ表示z的标准差。标准差的平方σ2​​称为z的方差。高斯函数的曲线如图所示。

十一、图像平滑:

图像平滑从信号处理的角度看就是去除其中的高频信息,保留低频信息。因此我们可以对图像实施低通滤波。低通滤波可以去除图像中的噪声,对图像进行平滑。
根据滤波器的不同可分为均值滤波,高斯滤波,中值滤波, 双边滤波。
1.均值滤波:cv.blur(src, ksize, anchor, borderType)
均值滤波是一种典型的线性滤波算法。它对一个滑动窗口内的所有像素的灰度级求平均值,然后用这个平均值来代替窗口中心像素的原灰度级。这种方法在处理图像时,实质上是将噪声的灰度值也代入了均值中,可能导致噪声向周围扩散,使得图像变得模糊,边缘不清晰。
参数:src:输入图像
ksize:卷积核的大小
anchor:默认值 (-1,-1) ,表示核中心
borderType:边界类型
2.高斯滤波:cv.GaussianBlur(src,ksize,sigmaX,sigmay,borderType)
二维高斯是构建高斯滤波器的基础,其概率分布函数如下所示:

G(x,y)的分布是一个突起的帽子的形状。这里的σ可以看作两个值,一个是x方向的标准差σx,另一个是y方向的标准差σy。当σx和σy取值越大,整个形状趋近于扁平;当σx和σy越小,整个形状越突起。

正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。计算平滑结果时,只需要将中心点作为原点,其他点按照其在正态曲线上的位置归一化后分配权重得到一个加权平均值,将该加权平均值赋给中心点即可。高斯平滑在从去除高斯噪声方面非常有效。
参数:src: 输入图像
ksize:高斯卷积核的大小,注意卷积核的宽度和高度都应为奇数,且可以不同
sigmaX: 水平方向的标准差
sigmaY: 垂直方向的标准差,默认值为0,表示与sigmaX相同
borderType:填充边界类型
3.中值滤波:cv.medianBlur(src, ksize )
中值滤波采用像素点邻域灰度值的中位数来代替该像素点的灰度值。中值滤波对椒盐噪声来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。
参数:src:输入图像
ksize:卷积核的大小

十二、直方图:

直方图是对数据进行统计的一种方法,并且将统计值组织到一系列实现定义好的bin当中。bin为直方图中经常用到的一个概念,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。
图像直方图(Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素个数。这种直方图中,横坐标的左侧为较暗的区域,而右侧为较亮的区域。因此一张较暗图片的直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。直方图是根据灰度图进行绘制的,假设有一张图像的信息(灰度值 0 - 255,已知数字的范围包含 256 个值,于是可以按一定规律将这个范围分割成子区域(也就是 bins),[0,255]=[0,15]⋃[16,30]⋯⋃[240,255][0,255]=[0,15]⋃[16,30]⋯⋃[240,255],然后再统计每一个 bin(i) 的像素数目。可以得到下图(其中 x 轴表示 bin,y 轴表示各个 bin 中的像素个数):

直方图的一些术语和细节:
dims:需要统计的特征数目。在上例中,dims = 1 ,因为仅仅统计了灰度值。
bins:每个特征空间子区段的数目,在上例中, bins = 16。
range:要统计特征的取值范围。在上例中,range = [0, 255]。
1.直方图的计算:
cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])
参数:images: 原图像。当传入函数时应该用中括号 [] 括起来,例如:[img]。
channels: 如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入 的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。   
mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计 图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。
histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。   
ranges: 像素值范围,通常为 [0,256]
返回值:一个规模为1*ranges/bins的矩阵,其中每个值分别是对应bins的像素个数
2.掩膜:掩膜是用选定的图像、图形或物体,对要处理的图像进行遮挡,来控制图像处理的区域。在数字图像处理中,我们通常使用二维矩阵数组进行掩膜。掩膜是由0到255组成一个二进制图像,利用该掩膜图像要处理的图像进行掩膜,其中255值的区域被处理,0 值区域被屏蔽,不会处理。中间值则是部分掩膜。
我们使用cv.calcHist()来查找完整图像的直方图,如果要查找图像某些区域的直方图,只需在要查找直方图的区域上创建一个白色的掩膜图像,否则创建黑色,然后将其作为掩码mask传递即可。
3.直方图均衡化:dst = cv.equalizeHist(img)
如果一副图像中的大多数像素点的像素值都集中在某一个小的灰度值值范围之内会怎样呢?如果一幅图像整体很亮,那所有的像素值的取值个数应该都会很高。所以应该把它的直方图做一个横向拉伸,就可以扩大图像像素值的分布范围,提高图像的对比度,这就是直方图均衡化要做的事情。直方图均衡化是把原始图像的灰度直方图从比较集中的某个灰度区间变成在更广泛灰度范围内的分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。这种方法提高图像整体的对比度,特别是有用数据的像素值分布比较接近时,在X光图像中使用广泛,可以提高骨架结构的显示,另外在曝光过度或不足的图像中可以更好的突出细节。
参数:img: 灰度图像
返回值:均衡化后的结果
4.自适应直方图均衡化:cv.createCLAHE(clipLimit, tileGridSize)
上述的直方图均衡,我们考虑的是图像的全局对比度。的确在进行完直方图均衡化之后,图片背景的对比度被改变了,在许多情况下,这样做的效果并不好。为了解决这个问题,需要使用自适应的直方图均衡化。此时,整幅图像会被分成很多小块,这些小块被称为tiles(默认8x8),然后再对每一个小块分别进行直方图均衡化。所以在每一个的区域中,直方图会集中在某一个小的区域中。如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的 bin 超过对比度的上限的话,就把其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。最后,为了除每一个小块之间的边界,再使用双线性差值,对每一小块进行拼接。
参数:clipLimit: 对比度限制,默认是40
tileGridSize: 分块的大小,默认为8∗8
返回值:自适应均衡化的对象,需要应用于图像cl1 = clahe.apply(img)

十三、边缘检测:

边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。
图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部分可以划分为两类:基于搜索和基于零穿越。
基于搜索:通过寻找图像一阶导数中的最大值来检测边界,然后利用计算结果估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值,代表算法是Sobel算子和Scharr算子。
基于零穿越:通过寻找图像二阶导数零穿越来寻找边界,代表算法是Laplacian算子。
1.sobel算子:cv2.Sobel(src, depth, dx, dy, dst, ksize, scale, delta, borderType)
参数:src:传入的图像
depth: 图像的深度
dx和dy: 指求导的阶数,0表示这个方向上没有求导,取值为0、1。
ksize: 是Sobel算子(卷积核)的大小,必须为奇数1、3、5、7,默认为3。
如果ksize=-1,就演变成为3x3的Scharr算子。
scale:缩放导数的比例常数,默认情况为没有伸缩系数。
borderType:图像边界的模式,默认值为cv2.BORDER_DEFAULT。
Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S。处理完图像后,再使用cv2.convertScaleAbs()函数将其转回原来的uint8格式,否则图像无法显示。Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted( )函数将其组合起来。
Scale_abs = cv2.convertScaleAbs(x) # 格式转换函数
result = cv2.addWeighted(src1, alpha, src2, beta) # 图像混合

2.Laplacian算子:cv2.Laplacian(src,depth,dst,ksize,scale, delta, borderType)

参数:src: 需要处理的图像,
depth: 图像的深度,-1表示采用的是原图像相同的深度,注意目标图像的深度必须 大于等于原图像的深度;
ksize:算子的大小,即卷积核的大小,必须为1,3,5,7。
3.Canny算子:cv2.Canny(image, threshold1, threshold2)
Canny 边缘检测算法是一种非常流行的边缘检测算法,被认为是最优的边缘检测算法。
Canny边缘检测算法由4步构成,分别介绍如下:
①噪声去除:由于边缘检测很容易受到噪声的影响,所以首先使用5*5高斯滤波器去除噪声,在图像平滑那一章节中已经介绍过。
②计算图像梯度:对平滑后的图像使用Sobel算子计算水平方向和竖直方向的一阶导数(Gx 和 Gy)。根据得到的这两幅梯度图(Gx 和 Gy)找到边界的梯度和方向,公式如下:

如果某个像素点是边缘,则其梯度方向总是垂直与边缘垂直。梯度方向被归为四类:垂直,水平,和两个对角线方向。
③非极大值抑制:在获得梯度的方向和大小之后,对整幅图像进行扫描,去除那些非边界上的点。对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。如下图所示:

A点位于图像的边缘,在其梯度变化方向,选择像素点B和C,用来检验A点的梯度是否为极大值,若为极大值,则进行保留,否则A点被抑制,最终的结果是具有“细边”的二进制图像。
④滞后阈值:现在要确定真正的边界。我们设置两个阈值:minVal和maxVal。当图像的灰度梯度高于maxVal时被认为是真的边界,低于minVal的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。
参数:image:灰度图,
threshold1: minval,较小的阈值将间断的边缘连接起来
threshold2: maxval,较大的阈值检测图像中明显的边缘

十四、模板匹配:cv.matchTemplate(img,template,method)

所谓的模板匹配,就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑窗的思路不断的移动模板图片,计算其与图像中对应区域的匹配度,最终将匹配度最高的区域选择为最终的结果。其实现流程是:
准备两幅图像:原图像(I)和模板(T),滑动模板图像和原图像进行比对,将模板块每次移动一个像素 (从左往右,从上往下),在每一个位置都计算与模板图像的相似程度。
对于每一个位置将计算的相似结果保存在结果矩阵(R)中。查找R最大值所在的位置,那么该位置对应的区域就被认为是最匹配的。对应的区域就是以该点为顶点,长宽和模板图像一样大小的矩阵。
参数:img: 要进行模板匹配的图像
Template:模板
method:实现模板匹配的算法,主要有:
平方差匹配(CV_TM_SQDIFF):利用模板与图像之间的平方差进行匹配,最好的匹配 是0,匹配越差,匹配的值越大。
相关匹配(CV_TM_CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配 程度较高,越小表示匹配效果差。
相关系数匹配(CV_TM_CCOEFF):利用模板与图像间的相关系数匹配,1表示完美 的匹配,-1表示最差的匹配。
完成匹配后,使用cv.minMaxLoc()方法查找最大值所在的位置即可。如果使用平方差作为比较方法,则最小值位置是最佳匹配位置。
需要注意的是,模板匹配不适用于尺度变换,视角变换后的图像我们需要使用关键点匹配算法,比较经典的关键点检测算法包括SIFT和SURF等,主要的思路是首先通过关键点检测算法获取模板和测试图片中的关键点;然后使用关键点匹配算法处理即可,这些关键点可以很好的处理尺度变化、视角变换、旋转变化、光照变化等,具有很好的不变性。

十五、霍夫变换:

霍夫变换常用来提取图像中的直线和圆等几何形状,如下图所示:

霍夫线检测:cv.HoughLines(img, rho, theta, threshold)
参数:img: 检测的图像,要求是二值化的图像
rho、theta: ρ 和θ的精确度
threshold: 阈值,只有累加器中的值高于该阈值时才被认为是直线。
霍夫圆检测:OpenCV中使用霍夫梯度法进行圆形的检测。原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数就多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图形的检测中。霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。由于霍夫圆检测对噪声比较敏感,所以首先对图像进行中值滤波。
cv.HoughCircles(image, method, dp, minDist, param1, param2, minRadius,
maxRadius)
参数:image:输入图像,应输入灰度图像
method:使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT
dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2 时霍夫空间是输入图像空间的一半,以此类推
minDist为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认 为它们是同一个圆心
param1:边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。
param2:检测圆心和确定半径时所共有的阈值
minRadius和maxRadius为所检测到的圆半径的最小值和最大值
返回值:输出圆向量,包括三个浮点型的元素——圆心横坐标,圆心纵坐标和圆半径

十六、角点检测:

角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用。角点在三维场景重建运动估计,目标跟踪、目标识别、图像配准与匹配等计算机视觉领域起着非常重要的作用。
1.Harris角点检测:cv.cornerHarris(src, blockSize, ksize, k)
Harris角点检测的思想是通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化
参数:img:数据类型为 float32 的输入图像。
blockSize:角点检测中要考虑的邻域大小。
ksize:sobel求导使用的核大小
k:角点检测方程中的自由参数,取值参数为 [0.04,0.06].
2.Shi-Tomasi角点检测:
cv2.goodFeaturesToTrack ( image, maxcorners, qualityLevel, minDistance )
Shi-Tomasi算法是对Harris角点检测算法的改进,一般会比Harris算法得到更好的角点。Harris 算法的角点响应函数是将矩阵 M 的行列式值与 M 的迹相减,利用差值判断是否为角点。后来Shi 和Tomasi 提出改进的方法是,若矩阵M的两个特征值中较小的一个大于阈值,则认为他是角点。
参数:Image: 输入灰度图像
maxCorners : 获取角点数的数目。
qualityLevel:该参数指出最低可接受的角点质量水平,在0-1之间。
minDistance:角点之间最小的欧式距离,避免得到相邻特征点。
返回值:搜索到的角点,在这里所有低于质量水平的角点被排除掉,然后把合格的角点按质量排序,然后将质量较好的角点附近(小于最小欧式距离)的角点删掉,最后找到maxCorners个角点返回。
3.SIFT角点检测:前面两节我们介绍了Harris和Shi-Tomasi角点检测算法,这两种算法具有旋转不变性,但不具有尺度不变性,以下图为例,在左侧小图中可以检测到角点,但是图像被放大后,在使用同样的窗口,就检测不到角点了。所以,下面我们来介绍一种计算机视觉的算法,尺度不变特征转换即SIFT (Scale-invariant feature transform)。它用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。应用范围包含物体辨识、机器人地图感知与导航、影像缝合、3D模型建立、手势辨识、影像追踪和动作比对等领域。SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。
①实例化sift:sift = cv.xfeatures2d.SIFT_create()
②利用sift.detectAndCompute()检测关键点并计算:
kp,des = sift.detectAndCompute(gray,None)
参数:gray: 进行关键点检测的图像,注意是灰度图像
返回值:kp: 关键点信息,包括位置,尺度,方向信息
des: 关键点描述符,每个关键点对应128个梯度信息的特征向量
③将关键点检测结果绘制在图像上
cv.drawKeypoints(image, keypoints, outputimage, color, flags)
参数:image: 原始图像
keypoints:关键点信息,将其绘制在图像上
outputimage:输出图片,可以是原始图像
color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色
flags:绘图功能的标识设置
cv2.DRAW_MATCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出 图像绘制匹配对和特征点,对每一个关键点只绘制中间点
cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建输出图像矩阵, 而是在输出图像上绘制匹配对
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被 绘制
4.SURF算法:
SIFT在图像的不变特征提取方面拥有无与伦比的优势,但并不完美,仍然存在实时性不高,有时特征点较少,对边缘光滑的目标无法准确提取特征点等缺陷,自SIFT算法问世以来,人们就一直对其进行优化和改进,其中最著名的就是SURF算法。
SURF算法的应用与SIFT一致,这里就不在赘述。

十七、视频读写:

1.读取视频:cv.VideoCapture(filepath)
参数:filepath: 视频文件路径
2.获取视频的属性:cap.get(propId)
参数:propId: 视频的某个属性,具体见下

3.修改视频的属性:cap.set(propId,value)
参数:proid: 属性的索引,与上面的表格相对应
value: 修改后的属性值
4.判断图像是否读取成功:cap.isOpened()
5.获取视频的一帧图像:ret, frame = cap.read()
参数:ret: 若获取成功返回True,获取失败,返回False
Frame: 获取到的某一帧的图像
6.调用cv.imshow()显示图像,在显示图像时使用cv.waitkey()设置适当的持续时间,如果太低视频会播放的非常快,如果太高就会播放的非常慢,通常情况下设置25ms就可以。
7.释放视频资源:cap.release()
8.保存视频:cv2.VideoWriter(filename,fourcc, fps, frameSize)
参数:filename:视频保存的位置
fourcc:指定视频编解码器的4字节代码
fps:帧率
frameSize:帧大小
设置视频的编解码器,如下所示,retval = cv2.VideoWriter_fourcc( c1, c2, c3, c4 )
参数:c1,c2,c3,c4: 是视频编解码器的4字节代码,在fourcc.org中找到可用代码列表, 与平台紧密相关,常用的有:
在Windows中:DIVX(.avi)
在OS中:MJPG(.mp4),DIVX(.avi),X264(.mkv)。

十八、视频追踪:

1.meanshift算法:cv.meanShift(probImage, window, criteria)
假设你有一堆点集,还有一个小的窗口,这个窗口可能是任意形状的,现在你要移动这个窗口到点集密度最大的区域当中。

最开始的窗口是蓝色圆环的区域,命名为C1。蓝色圆环的圆心用一个蓝色的矩形标注,命名为C1_o。而窗口中所有点的点集构成的质心在蓝色圆形点C1_r处,显然圆环的形心和质心并不重合。所以,移动蓝色的窗口,使得形心与之前得到的质心重合。在新移动后的圆环的区域当中再次寻找圆环当中所包围点集的质心,然后再次移动,通常情况下,形心和质心是不重合的。不断执行上面的移动过程,直到形心和质心大致重合结束。 这样,最后圆形的窗口会落到像素分布最大的地方,也就是图中的绿色圈,命名为C2。meanshift算法除了应用在视频追踪当中,在聚类,平滑等等各种涉及到数据以及非监督学习的场合当中均有重要应用,是一个应用广泛的算法。
参数:probImage: ROI区域,即目标的直方图的反向投影
window: 初始搜索窗口,就是定义ROI的rect
criteria: 确定窗口搜索停止的准则,主要有迭代次数达到设置的最大值,窗口中心 的漂移值大于某个设定的限值等。
实现Meanshift的主要流程是:
读取视频文件:cv.videoCapture()
感兴趣区域设置:获取第一帧图像,并设置目标区域,即感兴趣区域
计算直方图:计算感兴趣区域的HSV直方图,并进行归一化
目标追踪:设置窗口搜索停止条件,直方图反向投影,进行目标追踪,并在目标位置绘 制矩形框。
2.camshift算法:连续自适应MeanShift算法,是对MeanShift算法的改进算法,可随着跟踪目标的大小变化实时调整搜索窗口的大小,具有较好的跟踪效果。Camshift算法首先应用meanshift,一旦meanshift收敛,它就会更新窗口的大小,还计算最佳拟合椭圆的方向,从而根据目标的位置和大小更新搜索窗口。
Camshift在OpenCV中实现时,只需将上述的meanshift函数改为Camshift函数即可

Mat头部:图片的长宽高,参数的数据类型,通道数

赋值a=b是改变指针,只有拷贝才能创建新的。