一、基本方法
1、cv2.imread()
读入图像;第一个参数为图像路径;第二个为cv2.IMREAD_COLOR:读入彩色图像;cv2.IMREAD_GRAYSCALE:读入灰度图像。
import cv2
import matplotlib.pyplot as plt
from PIL import Image
img_bgr = cv2.imread('../taobao.png')
h = 800
w = int(h*1.0/img_bgr.shape[0] * img_bgr.shape[1])
img_bgr2 = cv2.resize(img_bgr,dsize=None,fx=1.5,fy=1.5,interpolation=cv2.INTER_CUBIC)
"""
def resize(src, dsize, fx=None, fy=None, interpolation=None):
src: 原图像的array
dsize:tuple数据类型,(fx 轴像素,fy 轴像素), 换句话来讲,第一个元素为宽度,第二个元素才是高度
fx=None, fy=None : 与 dsize不同时使用,需要指定 dsize=None,指定源图像按 x轴 y轴 缩放的比例
"""
img_bgr3 = cv2.resize(img_bgr,dsize=(w,h),interpolation=cv2.INTER_CUBIC)
cv2.imshow('image1',img_bgr)
cv2.imshow('image2',img_bgr2)
cv2.imshow('image3',img_bgr3)
cv2.waitKey(5000) # 5000ms,5s 程序继续执行,当然可以点击键盘立即执行
"""
v2.waitkey(delay),delay 的单位为ms毫秒,
当 delay > 0 时,程序在给定的 delay 时间内等待用户按键触发 或者 等待一个delay时间,程序继续执行。
若 delay = 0 时,则表示用户必须点击键盘触发程序继续执行。
"""
cv2.destroyAllWindows()
print("finish")
2、显示图像cv2.imshow()
cv2.imshow('image1',img_bgr)
cv2.imshow('image2',img_bgr2)
cv2.imshow('image3',img_bgr3)
cv2.waitKey(5000) # 5000ms,5s 程序继续执行,当然可以点击键盘立即执行
"""
v2.waitkey(delay),delay 的单位为ms毫秒,
当 delay > 0 时,程序在给定的 delay 时间内等待用户按键触发 或者 等待一个delay时间,程序继续执行。
若 delay = 0 时,则表示用户必须点击键盘触发程序继续执行。
"""
cv2.destroyAllWindows()
3、保存图像cv2.imwrite()
4、获取视频先创建一个videocapture对象。参数可以是设备索引号或视频文件。
二、绘图函数:
需要设置一些参数:img:绘制图形的图像;color:颜色,元组(255,0,0);thickness:线条粗细;linetype:线条类型。
1、画线:cv2.line()
线条的起始点;
2、画矩阵:cv2.rectangle()
左上角顶点和右下角顶点坐标。
3、画圆:cv2.circle()
;+圆形的中心点和半径。
4、画椭圆cv2.ellipse()
;+中心点坐标+长轴和短轴的长度。
5、画多边形
6、在图片上添加文字:
绘制的文字+绘制的位置+字体类型+字体大小+文字一般属性(颜色,粗细+线条类型)
三、图像的基本操作
(1)获取并修改像素值
对BGR图像而言,返回BGR的值。对灰度图像,返回灰度值。px=img[100,100]
(2)获取图像属性
包括:行、列、通道以及图像数据类型,像素数目。
img.shape;img.size;img.dtype;
(3)图像ROI
对图像特定区域操作。切片处理。
(4)拆分及合并图像通道
(5)图像扩边(填充)
cv2.copyMakeBorder()函数,参数:输入图像+上下左右边界像素数目+边界颜色。。。
五、图像的算术运算
(1)图像加法
cv2.add()。两幅图像大小,类型必须一致,或第二个图像是一简单的标量。
numpy的加法则是一种求模操作。
(2)图像混合
cv2.addWeighted()
(3)按位运算
AND,OR,NOT,XOR等。当提取图像的一部分,选择非矩形ROI时有用。一般,两幅图叠加,使用加法,颜色会改变,使用混合,会得到透明效果。
六、OpenCV中的图像处理
颜色空间转换
(1)转换颜色空间 一般为BGR--GRAY和BGR--HSV。
cv2.cvtColor(img,flag) flag=cv2.COLOR_BGR2GRAY或cv2.COLOR_BGR2HSV
(2)物体跟踪
从视频中获取每一帧图像;将图像转换到HSV空间;设置HSV阈值到蓝色范围;获取蓝色物体。
(3)怎样找到要跟踪对象的HSV值?
cv2.cvtColor()
七、几何变换
OpenCV提供两个变换函数:cv2.warpAffine和cv2.warpPerspective。第一个接收函数为2*3的变换矩阵;第二个接收参数为3*3的变换矩阵。
(1)扩展缩放
cv2.resize()
img_bgr2 = cv2.resize(img_bgr,dsize=None,fx=1.5,fy=1.5,interpolation=cv2.INTER_CUBIC)
"""
def resize(src, dsize, fx=None, fy=None, interpolation=None):
src: 原图像的array
dsize:tuple数据类型,(fx 轴像素,fy 轴像素), 换句话来讲,第一个元素为宽度,第二个元素才是高度
fx=None, fy=None : 与 dsize不同时使用,需要指定 dsize=None,指定源图像按 x轴 y轴 缩放的比例
"""
interpolation 选项 | 所用的插值方法 |
INTER_NEAREST | 最近邻插值 |
INTER_LINEAR | 双线性插值(默认设置) |
INTER_AREA | 使用像素区域关系进行重采样。 它可能是图像抽取的首选方法,因为它会产生无云纹理的结果。 但是当图像缩放时,它类似于INTER_NEAREST方法。 |
INTER_CUBIC | 4x4像素邻域的双三次插值 |
INTER_LANCZOS4 | 8x8像素邻域的Lanczos插值 |
(2)平移
移动距离为tx,ty。然后传给函数cv2.warpAffine()。
(3)旋转
给图像一个旋转角度,
提供cv2.getRotationMatrix2D函数构建上旋转矩阵。
(4)仿射变换
在仿射变换中,原图中所有的平行线在结果图像中同样平行。为了创建该矩阵,须从原图像中找到三个点以及它们在输出图像中的位置。然后cv2.getAffineTransform会创建一个2*3的矩阵,最后传入函数cv2.warpAffine()。
(5)透视变换
须在输入图像上找4个点,以及在输出图像上的对应位置,四点中任意三点不共线。
八、图像阈值
(1)简单阈值
像素值高于阈值时,给该像素赋予一个新值。
cv2.threshold() 参数:img+对像素值进行分类的阈值+高于阈值时应被赋予的新的像素值+不同的阈值方法。
(2)自适应阈值
阈值根据图像上的每一个小区域计算与其对应的阈值,在同一幅图像上的不同区域采用不同的阈值。
cv2.adaptiveThreshold() 参数:计算阈值的方法+blocksize邻域大小(计算阈值的区域大小)+C常数。
(3)Otsu's二值化
简单来说就是对一副双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法得到的结果可能会不理想)。
九、图像平滑(图像模糊)
对2D图像实施低通滤波(LPF),高通滤波(HPF)等。
LPF帮助去除噪音,模糊图像。HPF帮助找到图像边缘。
cv2.filter2D()对图像进行卷积操作。
(1)平均
归一化卷积框完成,
用卷积框覆盖区域所有像素的平均值来代替中心元素。
cv2.blur()和cv2.boxFilter()
(2)高斯模糊
卷积核换成高斯核。实现函数为cv2.GaussianBlur()。需要指定高斯核的宽高,以及高斯函数沿X,Y方向的标准差。
(3)中值模糊
用与卷积框对应的像素中值来代替中心像素的值。经常用于去除椒盐噪声。
(4)双边滤波
在保持边界清晰的情况下有效的去除噪音。
十、形态学转换
形态学操作是根据图像形状进行的简单操作。一般情况下对二值化图像进行的操作。
两个基本的形态学操作是腐蚀和膨胀。它们的变体构成了开运算,闭运算,梯度等。
(1)腐蚀
卷积核沿着图像滑动,如果与卷积核对应的原图像的所有像素值都是1,那么中心元素就保持原来的像素值,否则就变为零。
根据卷积核的大小靠近前景的所有像素都会被腐蚀掉(变为0),所以前景物体会变小,整幅图像的白色区域会减少。这对于去除白噪声很有用,也可以用来断开两个连在一块的物体等。
(2)膨胀
与腐蚀相反,与卷积核对应的原图像的像素值中只要有一个是1,中心元素的像素值就是1。所以这个操作会增加图像中的白色区域(前景)。一般在去噪声时先用腐蚀再用膨胀。因为腐蚀在去掉白噪声的同时,也会使前景对象变小。所以我们再对他进行膨胀。这时噪声已经被去除了,不会再回来了,但是前景还在并会增加。膨胀也可以用来连接两个分开的物体。
(3)开运算
先腐蚀再膨胀。用于去除噪声。
(4)闭运算
先膨胀再腐蚀。被用于填充前景物体中的小洞,或前景物体上的小黑点。
(5)形态学梯度
图像膨胀与腐蚀的差别。前景物体的轮廓。
(6)礼帽
原始图像与进行开运算之后得到的图像的差。
(7)黑帽
进行闭运算之后得到的图像与原始图像的差。
结构化元素
一般使用Numpy构建结构化元素,是正方形的。有时也需要构建一个椭圆形/圆形的核。
十一、图像梯度
梯度简单来说就是求导。OpenCV提供了三种不同的梯度滤波器,或者高通滤波器:sobel;scharr和laplacian。
Sobel,Scharr 其实就是求一阶或二阶导数。Scharr 是对Sobel(使用小的卷积核求解求解梯度角度时)的优化。Laplacian 是求二阶导数。
canny边缘检测
噪声去除(5*5高斯滤波器去除噪声);计算图像梯度(对平滑后的图像使用sobel算子计算水平和竖直方向的一阶导数,根据梯度图找到边界梯度和方向);非极大值抑制(去除非边界上的点,查看是否是周围具有相同梯度方向中的点最大的);
滞后阈值(确定真正的边界,设置两个阈值。当图像的灰度梯度高于maxVal 时被认为是真的边界,那些低于minVal 的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃)。
在OpenCV中cv2.Canny()就可以完成以上几步。第一个参数是输入图像。第二和第三个分别是minVal 和maxVal。第三个参数设置用来计算图像梯度的Sobel卷积核的大小,默认值为3。最后一个参数是L2gradient,它可以用来设定求梯度大小的方程。
图像金子塔
创建一组图像,这些图像是具有不同分辨率的原始图像。
有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。
高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中5个像素的高斯加权平均值。M*N--M/2*N/2.
使用函数cv2.pyrDown()和cv2.pyrUp()构建图像金字塔。
cv2.pyrDown()从一个高分辨率大尺寸的图像向上构建一个金字塔(尺寸变小,分辨率降低)。
函数cv2.pyrUp() 从一个低分辨率小尺寸的图像向下构建一个金子塔(尺寸变大,但分辨率不会增加)。
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是0。经常被用在图像压缩中。
使用金子塔进行图像融合。
读入两幅图像;构建图像的高斯金字塔;根据高斯金字塔计算拉普拉斯金字塔;在拉普拉斯的每一层进行图像融合;根据融合后的图像金字塔重建原始图像。
OpenCV中的轮廓
(1)轮廓简单认为是将连续的点连在一起的曲线,具有相同的颜色或灰度。
为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者Canny 边界检测。
查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中。
函数cv2.findContours() 有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。
返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。
轮廓(第二个返回值)是一个Python列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个Numpy 数组,包含对象边界点(x,y)的坐标。
函数cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置为-1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。
(2)轮廓特征
查找轮廓不同的特征,如面积,周长,重心,边界框等。
矩:可以帮助计算图像的质心,面积。计算的矩以字典形式返回。
轮廓面积:轮廓的面积可以使用函数cv2.contourArea() 计算得到,也可以使用矩(0 阶矩),M['m00']。
轮廓周长:
也被称为弧长。可以使用函数cv2.arcLength() 计算得到。这个函数的第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。
轮廓近似:
将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由设定的准确度来决定。
凸包:函数cv2.convexHull() 可以用来检测一个曲线是否具有凸性缺陷,并能纠正缺陷。一般来说,凸性曲线总是凸出来的,至少是平的。如果有地方凹进去了就被叫做凸性缺陷。
points 要传入的轮廓;clockwise 方向标志。如果设置为True,输出的凸包是顺时针方向的。否则为逆时针方向。returnPoints 默认值为True。它会返回凸包上点的坐标。如果设置为False,就会返回与凸包点对应的轮廓上的点。
凸性检测:函数cv2.isContourConvex() 可以可以用来检测一个曲线是不是凸的。它只能返回True 或False。
边界矩形:
直边界矩形:直矩形就是没有旋转的矩形,不会考虑对象是否旋转。可以使用函数cv2.boundingRect() 查找得到。
旋转的边界矩形:考虑了对象的旋转。用到的函数为cv2.minAreaRect()。返回的是一个Box2D 结构,其中包含矩形左上角角点的坐标(x,y),矩形的宽和高(w,h),以及旋转角度。但是要绘制这个矩形需要矩形的4 个角点,可以通过函数cv2.boxPoints() 获得。
最小外接圆:函数cv2.minEnclosingCircle() 可以找到一个对象的外切圆。它是所有能够包括对象的圆中面积最小的一个。
椭圆拟合:使用的函数为cv2.fitEllipse(),返回值其实就是旋转边界矩形的内切圆。
直线拟合:cv2.fitLine()可以根据一组点拟合出一条直线,同样也可以为图像中的白色点拟合出一条直线。
轮廓的性质:
长宽比:
extent:轮廓面积与边界矩形面积比。
Solidity:轮廓面积与凸包面积的比。
Equivalent Diameter:与轮廓面积相等的圆形直径:
方向:对象的方向
掩模与像素点:
最大值和最小值以及它们的位置:
平均颜色及平均灰度:使用相同的掩模求一个对象的平均颜色或平均灰度。
极点:对象最上下左右的点。
轮廓:更多函数。凸缺陷;点到多边形的最短距离;形状匹配。
凸缺陷:
Point Polygon Test:求解图像中的一个点到一个对象轮廓的最短距离。如果点在轮廓的外部,返回值为负。如果在轮廓上,返回值为0。如果在轮廓内部,返回值为正。
此函数的第三个参数是measureDist。如果设置为True,就会计算最短距离。如果是False,只会判断这个点与轮廓之间的位置关系(返回值为+1,-1,0)。
形状匹配:函数cv2.matchShape() 可以比较两个形状或轮廓的相似度。如果返回值越小,匹配越好。
直方图
通过直方图可以对整幅图像的灰度分布有一个整体的了解。直方图的x轴是灰度值,y轴是图片中具有同一灰度值的点的数目。
直方图的左边区域像是了暗一点的像素数量,右侧显示了亮一点的像素的数量。
函数cv2.calcHist 可以帮助统计一幅图像的直方图。
Numpy 中的函数np.histogram() 也可以统计直方图。
绘制直方图:Matplotlib 中有直方图绘制函数:matplotlib.pyplot.hist()。它可以直接统计并绘制直方图。
使用掩模:要统计图像某个局部区域的直方图只需要构建一副掩模图像。将要统计的部分设置成白色,其余部分为黑色,就构成了一副掩模图像。然后把这个掩模图像传给函数就可以了。
直方图均衡化
将直方图横向拉伸。直方图均衡化经常用来使所有的图片具有相同的亮度条件的参考工具。这在很多情况下都很有用。例如,脸部识别,在训练分类器前,训练集的所有图片都要先进行直方图均衡化从而使它们达到相同的亮度条件。
CLAHE 有限对比适应性直方图均衡化
直接的直方图均衡化会改变图像的对比度。
2D直方图
以上的直方图是一维的。因为只考虑了图像的一个特征:灰度值。
对于彩色图像的直方图通常情况下需要考虑每个颜色Hue和饱和度Saturation。根据这两个特征绘制2D直方图。
使用函数cv2.calcHist() 来计算直方图既简单又方便。如果要绘制颜色直方图的话,我们首先需要将图像的颜色空间从BGR 转换到HSV。(记住,计算一维直方图,要从BGR 转换到HSV)。
绘制2D直方图
使用cv2.imshow(),得到的结果是180*256的两维数组。
可以使用matplotlib.pyplot.imshow()。
直方图反向投影
可以用来做图像分割,或者在图像中找寻我们感兴趣的部分。简单来说,它会输出与输入图像(待搜索)同样大小的图像,其中
的每一个像素值代表了输入图像上对应点属于目标对象的概率。用更简单的话来解释,输出图像中像素值越高(越白)的点就越可能代表我们要搜索的目标(在输入图像所在的位置)。这是一个直观的解释。直方图投影经常与camshift算法等一起使用。
OpenCV 提供的函数cv2.calcBackProject() 可以用来做直方图反向投影。其中的参数是要查找目标的直方图。同样再使用之前应先对其做归一化处理。返回的结果是一个概率图像,再使用一个圆盘形卷积核对其做卷操作,最后使用阈值进行二值化。
图像变换
傅里叶变换
使用2D离散傅里叶变换(DFT)分析图像的频域特性。实现DFT的一个快速算法为快速傅里叶变化(FFT)。
函数np.fft.fft2() 可以对信号进行频率转换,输出结果是一个复杂的数组。
OpenCV 中相应的函数是cv2.dft() 和cv2.idft()。输出的结果是双通道的。第一个通道是结果的实数部分,第二个通道是结果的虚数部分。输入图像要首先转换成np.float32 格式。
模板匹配
模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。
如果输入图像的大小是(WxH),模板的大小是(wxh),输出的结果的大小就是(W-w+1,H-h+1)。当你得到这幅图之后,就可以使用函数cv2.minMaxLoc() 来找到其中的最小值和最大值的位置了。第一个值为矩形左上角的点(位置),(w,h)为moban 模板矩形的宽和高。这个矩形就是找到的模板区域了。
多对象的模板匹配
霍夫Hough直线变换
霍夫变换在检测各种形状的的技术中非常流行,如果要检测的形状可以用数学表达式写出,就可以是使用霍夫变换检测它。
函数:cv2.HoughLines()。返回值就是(p;o)。p 的单位是像素,o 的单位是弧度。第一个参数是一个二值化图像,所以在进行霍夫变换之前要首先进行二值化,或者进行Canny 边缘检测。第二和第三个值分别代表p 和o 的精确度。第四个参数是阈值,只有累加其中的值高于阈值时才被认为是一条直线,也可以把它看成能检测到的直线的最短长度(以像素点为单位)。
Hough 霍夫圆环变换
一个圆环需要3个参数来确定。所以进行圆环霍夫变换的累加器必须是3 维的,这样的话效率就会很低。所以OpenCV 用来一个比较巧妙的办法,霍夫梯度法,它可以使用边界的梯度信息。
分水岭算法图像分割
任何一副灰度图像都可以被看成拓扑平面,灰度值高的区域可以被看成是山峰,灰度值低的区域可以被看成是山谷
使用GrabCut算法进行交互式前景提取
Harris角点检测
Open 中的函数cv2.cornerHarris() 可以用来进行角点检测。参数:img - 数据类型为float32 的输入图像。• blockSize - 角点检测中要考虑的领域大小。• ksize - Sobel 求导中使用的窗口大小。• k - Harris 角点检测方程中的自由参数,取值参数为[0,04,0.06].
Shi-Tomasi 角点检测& 适合于跟踪的图像特征
OpenCV 提供了函数:cv2.goodFeaturesToTrack()。这个函数使用Shi-Tomasi 方法获取图像中N 个最好的角点。
通常情况下,输入的应该是灰度图像。然后确定你想要检测到的角点数目。再设置角点的质量水平,0到1 之间。它代表了角点的最低质量,低于这个数的所有角点都会被忽略。最后在设置两个角点之间的最短欧式距离。
尺度不变特征变换SIFT(Scale-Invariant Feature Transform)
函数sift.detect() 可以在图像中找到关键点。如果你只想在图像中的一个区域搜索的话,也可以创建一个掩模图像作为参数使用。返回的关键点是一个带有很多不同属性的特殊结构体,这些属性中包含它的坐标(x,y),有意义的邻域大小,确定其方向的角度等。
SIFT算法使用的是128维的描述符。
OpenCV 也提供了绘制关键点的函数:cv2.drawKeyPoints(),它可以在关键点的部位绘制一个小圆圈。
加速稳健特征SURF(Speeded-Up Robust Features)
角点检测的FAST 算法
非极大值抑制:使用非极大值抑制方法可以解决检测到的特征点相连的问题。
BRIEF(Binary Robust Independent ElementaryFeatures)
在实际的匹配过程中如此多的维度是没有必要的。可以使用PCA,LDA 等方法来进行降维。甚至可以使用LSH(局部敏感哈希)将SIFT 浮点数的描述符转换成二进制字符串。对这些字符串再使用汉明距离进行匹配。汉明距离的计算只需要进行XOR 位运算以及位计数。
BRIEF不去计算描述符而是直接找到一个二进制字符串。
BRIEF 是一种特征描述符,它不提供查找特征的方法。所以我们不得不使用其他特征检测器,比如SIFT 和SURF 等。
使用了CenSurE 特征检测器和BRIEF 描述符。(在OpenCV中CenSurE 检测器被叫做STAR 检测器)
ORB (Oriented FAST and Rotated BRIEF)
ORB 基本是FAST 关键点检测和BRIEF 关键点描述器的结合体,并通过很多修改增强了性能。首先它使用FAST 找到关键点,然后再使用Harris角点检测对这些关键点进行排序找到其中的前N 个点。它也使用金字塔从而产生尺度不变性特征。
特征匹配
Brute-Force 匹配:蛮力匹配。首先在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行距离测试,最后返回距离最近的关键点。
首先要使用cv2.BFMatcher() 创建一个BFMatcher对象。它有两个可选参数。第一个是normType。它是用来指定要使用的距离测试类型。默认值为cv2.Norm_L2。。这很适合SIFT 和SURF 等(c2.NORM_L1 也可以)。对于使用二进制描述符的ORB,BRIEF,BRISK算法等,要使用cv2.NORM_HAMMING,这样就会返回两个测试对象之间的汉明距离。
第二个参数是布尔变量crossCheck,默认值为False。如果设置为True,匹配条件就会更加严格,只有到A 中的第i 个特征点与B 中的第j 个特征点距离最近,并且B 中的第j 个特征点到A 中的第i 个特征点也是最近(A 中没有其他点到j 的距离更近)时才会返回最佳匹配(i,j)。也就是这两个特征点要互相匹配才行。
BFMatcher 对象具有两个方法,BFMatcher.match() 和BFMatcher.knnMatch()。第一个方法会返回最佳匹配。第二个方法为每个关键点返回k 个最佳匹配(降序排列之后取前k 个),其中k 是由用户设定的。
FLANN匹配器
FLANN是快速最近邻搜索包。它是一个对大数据集和高维特征进行最近邻搜索的算法的集合。
使用FLANN匹配,需要传入两个字典作为参数,其用来确定要使用的算法和其他相关参数等。
第一个是IndexParams;第二个字典是SearchParams,用来指定递归遍历次数。
MeanShift和Camshift
将新窗口的中心移动到新的质心。不停的迭代操作直到窗口的中心和其所包含点的质心重合为止(或者有一点小误差)。按照这样的操作我们的窗口最终会落在像素值(和)最大的地方。
要在OpenCV 中使用Meanshift 算法,首先要对目标对象进行设置,计算目标对象的直方图,这样在执行meanshift 算法时就可以将目标对象反向投影到每一帧中去了。另外还需要提供窗口的起始位置。在这里计算H(Hue)通道的直方图,同样为了避免低亮度造成的影响,使用函数cv2.inRange() 将低亮度的值忽略掉。
MeanShift的窗口的大小是固定的,而汽车由远及近(在视觉上)是一个逐渐变大的过程,固定的窗口是不合适的。所以需要根据目标的大小和角度来对窗口的大小和角度进行修订。OpenCVLabs 带来的解决方案:一个被叫做CAMshift 的算法。
这个算法首先要使用meanshift,meanshift 找到(并覆盖)目标之后,再去调整窗口的大小 。它还会计算目标对象的最佳外接椭圆的角度,并以此调节窗口角度。然后使用更新后的窗口大小和角度来在原来的位置继续进行meanshift。重复这个过程知道达到需要的精度。
光流
由于目标对象或者摄像机的移动造成的图像对象在连续两帧图像中的移动被称为光流。它是一个2D 向量场,可以用来显示一个点从第一帧图像到第二帧图像之间的移动。
OpenCV 中的Lucas-Kanade 光流:cv2.calcOpticalFlowPyrLK();计算一些特征点的光流
OpenCV 中的稠密光流:计算图像中所有点的光流。
背景减除
从静止的背景提取出移动的前景
BackgroundSubtractorMOG
以混合高斯模型为基础的前景/背景分割算法。它使用K(K=3 或5)个高斯分布混合对背景像素进行建模。使用这些颜色(在整个视频中)存在时间的长短作为混合的权重。背景的颜色一般持续的时间最长,而且更加静止。
一个像素怎么会有分布呢?在x,y 平面上一个像素就是一个像素没有分布,但是现在讲的背景建模是基于时间序列的,因此每一个像素点所在的位置在整个时间序列中就会有很多值,从而构成一个分布。
需要使用函数:cv2.createBackgroundSubtractorMOG()创建一个背景对象。这个函数有些可选参数,比如要进行建模场景的时间长度,高斯混合成分的数量,阈值等。将他们全部设置为默认值。然后在整个视频中需要使用backgroundsubtractor.apply() 就可以得到前景的掩模了。
BackgroundSubtractorMOG2
这个算法的一个特点是它为每一个像素选择一个合适数目的高斯分布。(上一个方法中使用是K 高斯分布)。这样就会对由于亮度等发生变化引起的场景变化产生更好的适应。
和前面一样我们需要创建一个背景对象。但在可以选择是否检测阴影。如果detectShadows = True(默认值),它就会检测并将影子标记出来,但是这样做会降低处理速度。影子会被标记为灰色。
BackgroundSubtractorGMG
此算法结合了静态背景图像估计和每个像素的贝叶斯分割。
它使用前面很少的图像(默认为前120 帧)进行背景建模。使用了概率前景估计算法(使用贝叶斯估计鉴定前景)。这是一种自适应的估计,新观察到的对象比旧的对象具有更高的权重,从而对光照变化产生适应。一些形态学操作如开运算闭运算等被用来除去不需要的噪音。在前几帧图像中你会得到一个黑色窗口。
对结果进行形态学开运算对与去除噪声很有帮助。
K 近邻(k-Nearest Neighbour )
找出测试数据在特征空间的最近邻居。
仅仅检测最近的一个邻居是不足的,所有检测k个最近邻居。谁在k个邻居中占据多数,新成员就属于哪一类。
OpenCV中的kNN
kNN算法分类器的初始化。传入一个训练数据集,以及与训练数据集对应的分类来训练kNN分类器。
最后使用kNN分类器,测试数据。
设置返回的最近邻居的数目。返回值包括:1. 由kNN 算法计算得到的测试数据的类别标志(0 或1)。如果你想使用
最近邻算法,只需要将k 设置为1,k 就是最近邻的数目。2. k 个最近邻居的类别标志。3. 每个最近邻居到测试数据的距离。
使用kNN对手写数字OCR
OpenCV 安装包中有一副图片, 其中有5000 个手写数字(每个数字重复500遍)。每个数字是一个20x20 的小图。所以第一步就是将这个图像分割成5000个不同的数字。在将拆分后的每一个数字的图像重排成一行含有400 个像素点的新图像。这个就是我们的特征集,所有像素的灰度值。这是能创建的最简单的特征集。使用每个数字的前250 个样本做训练数据,剩余的250 个做测试数据。
使用SVM进行手写数据OCR
在kNN 中直接使用像素的灰度值作为特征向量。这次要使用方向梯度直方图Histogram of Oriented Gradients (HOG)作为特征向量。
在计算HOG 前,使用图片的二阶矩对其进行抗扭斜(deskew)处理。
K值聚类
这个算法是一个迭代过程。这些点到它们相应重心的距离之和最小。
OpenCV 中的函数cv2.kmeans() 对数据进行分类。
输入参数:1. samples: 应该是np.float32 类型的数据,每个特征应该放在一列。2. nclusters(K): 聚类的最终数目。3. criteria: 终止迭代的条件。当条件满足时,算法的迭代终止。它应该是一个含有3 个成员的元组,它们是(typw,max_iter,epsilon)。4. attempts: 使用不同的起始标记来执行算法的次数。算法会返回紧密度最好的标记。紧密度也会作为输出被返回。5. flags:用来设置如何选择起始重心。
输出参数:1. compactness:紧密度,返回每个点到相应重心的距离的平方和。2. labels:标志数组(与上一节提到的代码相同),每个成员被标记为0,1等。3. centers:由聚类的中心组成的数组。
颜色量化
颜色量化就是减少图片中颜色数目的一个过程。
现在有3 个特征:R,G,B。所以需要把图片数据变形成Mx3(M 是图片中像素点的数目)的向量。聚类完成后,用聚类中心值替换与其同组的像素值,这样结果图片就只含有指定数目的颜色了。