openCV知识点总结
知识点补充
RGB格式:图像像素由RGB三种颜色组合而成
灰度图:在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。一般常用的是加权平均法来获取每个像素点的灰度值。
二值图:图像的二值图,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。【特殊的灰度图像0 255】
引用库函数
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
openCV图像处理
图像读取:
cv2.imread 读取图片
cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道
cv2.IMREAD_GRAYSCALE:读入灰度图片
cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道
图像数据格式转换:
cv2.cvtColor 将图像格式转化
cv2.cvtColor(p1,p2) 是颜色空间转换函数,p1是需要转换的图片,p2是转换成何种格式。
cv2.COLOR_BGR2RGB 将BGR格式转换成RGB格式
cv2.COLOR_BGR2GRAY 将BGR格式转换成灰度图片
图像显示:
cv2.imShow()函数可以在窗口中显示图像。该窗口和图像的原始大小自适应(自动调整到原始尺寸)。第一个参数,窗口名称,第二个参数 图像数据(数据越界容易导致处理器挂掉)
cv2.imshow('image',img)
cv2.waitKey(10000)
cv2.destroyAllWindows()
图像数据保存:
cv2.imwrite('mycat.png',img) 将图像数据img保存为mycat.png
视频数据读取:
VideoCapture()中参数是0,表示打开笔记本的内置摄像头,参数是视频文件路径则打开视频,如cap = cv2.VideoCapture("../test.avi")
cv2.VideoCapture('test.mp4')
cap.read()按帧读取视频,ret,frame是获cap.read()方法的两个返回值。其中ret是布尔值,如果读取帧是正确的则返回True,如果文件读取到结尾,它的返回值就为False。frame就是每一帧的图像,是个三维矩阵。
vc = cv2.VideoCapture('test.mp4')
if vc.isOpened():
oepn, frame = vc.read() #按照帧读取
else:
open = False
颜色通道数据提取:
b,g,r=cv2.split(img)
将三种颜色通道的数据合并
img=cv2.merge((b,g,r))
边界填充:
cv2.copyMakeBorder
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
BORDER_REPLICATE 一种填充方式,填充的目的,增加数据(pading)
BORDER_REPLICATE:复制法,也就是复制最边缘像素。
BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT:常量法,常数值填充。
图像滤波操作:
线性滤波:图像滤波线性平滑变化(简而言之是经过数据函数计算求得中心点数据的方式滤波,效果:是图像变得模糊,缺点:噪音点过大,过滤效果不好)
均值滤波:
blur = cv2.blur(img, (3, 3))
方框滤波:(矩阵中心像素值是周围像素值得均值)
box = cv2.boxFilter(img,-1,(3,3), normalize=False)
均值滤波:(方框滤波的一种特殊滤波方式,即在方框滤波之前做了图像归一化操作)
box = cv2.boxFilter(img,-1,(3,3), normalize=True)
高斯滤波:高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的,矩阵中心的值为其周围像素点的数据经过加权叠加处理后得到的值,和方框滤波相似,但是不同于方框滤波的是数据权重大小会由中心点向四周以扩散的方式从大到小变化,而方框滤波 的数据权重相等。
aussian = cv2.GaussianBlur(img, (5, 5), 1)
非线性滤波:图像滤波非线性平滑变化(简而言之就是不经过连续函数处理得到,而是直接由离散数据中根据一定的规则选取到,优点,对于噪音较大的时候,过滤效果较好)
中值滤波:中心点数据 为该点邻域内所有像素点的中值点(非线性滤波)
图像腐蚀操作:解决图像中有较多毛刺的问题(噪音点的数据是离散分布的,毛刺相当于分布更加集中的噪音点)
kernel = np.ones((3,3),np.uint8) 规定腐蚀的核函数,即规定腐蚀操作的矩阵大小。
erosion = cv2.erode(img,kernel,iterations = 1) 腐蚀操作:腐蚀函数处理即为矩阵范围内使用当前值域内最小值赋值;iterations=1 表示腐蚀操作的迭代次数,即腐蚀操作的次数
图像膨胀操作:是图像中的毛刺更加突出,其原理和腐蚀操作相反,即核函数中数据使用当前矩阵值域内最大值赋值。
kernel = np.ones((3,3),np.uint8)
dige_dilate = cv2.dilate(dige_erosion,kernel,iterations = 1)
开运算:先腐蚀后膨胀 可以去掉毛刺、噪音点数据,这个效果和图像中值滤波的效果相似,不过比中值滤波更狠一些,中值滤波会有一些大的噪音点去不掉,二开运算会全部去掉
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
闭运算:先膨胀后腐蚀 不可以去掉毛刺,只是将一些噪音点数据去掉
kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
梯度运算:膨胀 - 腐蚀 用于突出毛刺、噪音点像素 部分边缘点
kernel = np.ones((5,5),np.uint8)
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
礼帽运算:原始数据 - 开运算结果 求解出毛刺和噪音点数据 少部分边缘点
kernel = np.ones((5,5),np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
黑帽运算:闭运算 - 原始数据,求解出噪音点的数据
图像的梯度运算:
Sobel算子:对中心点周围的像素进行右边减去左边 下边减去上边的操作
方法一:
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx) ##求差值的绝对值,否则只会显示一半
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')
方法二:(不建议使用)
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_show(sobelxy,'sobelxy')
图像梯度-laplacian算子:和Sobel算子不同,和高斯滤波权重选择方式相似
边缘检测:
Canny边缘检测¶
1) 使用高斯滤波器,以平滑图像,滤除噪声。【不明白为什么非要选择高斯滤波器】
2) 计算图像中每个像素点的梯度强度和方向。
3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。【】
4) 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
5) 通过抑制孤立的弱边缘最终完成边缘检测。
https://blog.csdn.net/tengfei461807914/article/details/76376941
非极大值抑制:首先获取图像上全部像素点的变化梯度方向以及大小后,然后对全图像进行扫描,去除不属于边界的点,检查每一个像素,看词像素是否是周围具有相同梯度方向中最大的。检测和后处理方法是:在同一方向上,比较当前点和旁边两个点的梯度值,如果当前点的梯度值是最大的,那么久把当前的点保存下来,否则就把当前的点抑制掉,即将其变为0。
边缘检测中使用到双阈值检测方法:首先设定两个阈值,一个是最大阈值和最小阈值,对于小于最小阈值的点直接判断为非边界点,对于大于最大阈值的直接判断为边界点,对于在最小阈值和最大阈值之间的值,如果判断点旁边是一个已经判断为边界点的点,那么当前前判断为边界点,否则判断为非边界点。
v1=cv2.Canny(img,80,150) #设置双阈值
v2=cv2.Canny(img,50,100)
res = np.hstack((v1,v2))
cv_show(res,'res')
高斯金字塔:1. 进行一个高斯内核的卷积操作 2. 向下采样 即将高斯层数据进行一个压缩(压缩方法 将偶数行和偶数列删除)3.向上采样,数据扩充,首先将数据扩充为原来的长宽的2倍,然后拿到扩充的结果,再使用高斯核进行卷积
上采样:up=cv2.pyrUp(img)
下采样:down=cv2.pyrDown(img)
图像轮廓:[参考:https://www.cnblogs.com/my-love-is-python/p/10402396.html]
cv2.findContours(img,mode,method)
mode:轮廓检索模式
- RETR_EXTERNAL :只检索最外面的轮廓;
- RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
- RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
- RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次; 一般只使用此参数
method:轮廓逼近方法
- CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
- CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) #获取轮廓的数据
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2) 传入绘制的图像 轮廓信息 绘制多少个轮廓(0:表示每次绘制一个 然后依次执行 -1表示绘制所有轮廓 (0, 0, 255)表示RGB值 2表示轮廓宽度 )
绘制边界矩形:
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) #二值处理
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) #获取边界像素点数据
cnt = contours[0] #获取第一组边界像素点数据
x,y,w,h = cv2.boundingRect(cnt) #根据边界像素点数据计算绘制矩形框的坐标位置以及长和宽
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')
图像傅里叶变化:低通滤波 高通滤波操作
1. cv2.dft(img, cv2.DFT_COMPLEX_OUTPUT) 进行傅里叶变化
参数说明: img表示输入的图片, cv2.DFT_COMPLEX_OUTPUT表示进行傅里叶变化的方法
2. np.fft.fftshift(img) 将图像中的低频部分移动到图像的中心
参数说明:img表示输入的图片
3. cv2.magnitude(x, y) 将sqrt(x^2 + y^2) 计算矩阵维度的平方根
参数说明:需要进行x和y平方的数
4.np.fft.ifftshift(img) # 进图像的低频和高频部分移动到图像原来的位置
参数说明:img表示输入的图片
5.cv2.idft(img) # 进行傅里叶的逆变化
参数说明:img表示经过傅里叶变化后的图片
傅里叶变化:将图像从空间域转换为频率域, 下面是傅里叶变化的公式
图像像素的均衡化处理:作用是图像增强 原理是根据直方图统计0 - 255像素值在图像中的分布,并统计各个灰度值得像素点频率,然后根据该频率乘以255得到均衡化的图像,使图像达到增强的效果。图像的均衡化是对整体图像的像素均衡,当图像中出现一些像素点比较突出的情况下,做了均衡化之后,会弱化这种比较突出的特征。
openCV 图像均衡化处理
均衡化-直方图显示
cv2.calcHist(images,channels,mask,histSize,ranges)
images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]
channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
mask: 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并 使用它。
histSize:BIN 的数目。也应用中括号括来
ranges: 像素值范围常为 [0256]
img = cv2.imread('cat.jpg',0) #0表示灰度图 读取图像数据
hist = cv2.calcHist([img],[0],None,[256],[0,256]) #读取直方图数据
plt.hist(img.ravel(),256)
plt.show() #根据直方图数据绘制直方图
创建于图像像素大小相同的掩码,并制定相应的范围为 255 其余则为 0
mask = np.zeros(img.shape[:2], np.uint8)
print (mask.shape)
mask[100:300, 100:400] = 255
cv_show(mask,'mask')
然后进行与操作,进而可以按照掩码的指定区域提取图像数据
img = cv2.imread('cat.jpg', 0)
masked_img = cv2.bitwise_and(img, img, mask=mask)#与操作
cv_show(masked_img,'masked_img')
均衡化处理操作:
equ = cv2.equalizeHist(img) #均衡化操作 缺点:图像均衡是对图像全局进行均衡,会导致有些局部突出特征被均衡到其他图像区域,即图像特征被弱化,为了解决此问题 因此可以选择自适应直方图均衡化
plt.hist(equ.ravel(),256) #绘制直方图
plt.show()
自适应直方图均衡化
equ = cv2.equalizeHist(img)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_clahe = clahe.apply(img)
res = np.hstack((img,equ,res_clahe)) #图像数据自适应
cv_show(res,'res'
openCV 模版匹配
模板匹配原理:
模板匹配类似于卷积原理。模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
TM_CCORR:计算相关性,计算出来的值越大,越相关
TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
img = cv2.imread('lena.jpg', 0) #读入源数据
template = cv2.imread('face.jpg', 0) #读入模板数据
h, w = template.shape[:2] #查看模板数据大小
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF) #选中一种图像差值计算方法
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) #导出计算的最大值 最小值 以及其对应的位置
不同计算方式的匹配操作
for meth in methods:
img2 = img.copy()
# 匹配方法的真值
method = eval(meth)
print (method)
res = cv2.matchTemplate(img, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 画矩形
cv2.rectangle(img2, top_left, bottom_right, 255, 2)
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.xticks([]), plt.yticks([]) # 隐藏坐标轴
plt.subplot(122), plt.imshow(img2, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
#源图像中有多处匹配项时候,可以选择根据匹配程度将所有坐标全部取出
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]): # *号表示可选参数
bottom_right = (pt[0] + w, pt[1] + h)
cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)
cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)
基于模板匹配的实战总结:首先需要处理模板数据,然后处理源图像数据,然后将保存的模板数据在源数据中根据指定的滑动窗口进行进行匹配
首先是模板数据处理:
1. 读入数据
img = cv2.imread(args["template"])
2.数据转换为灰度图后转换为二值图像
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref',ref)
3. 根据二值图像数据找到图像的轮廓边界点
refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
4. 轮廓边界点的返回值中包含每个轮廓位置及长宽等数据,取出数据,绘制模板轮廓矩形框、
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
for (i, c) in enumerate(refCnts):
# 计算外接矩形并且resize成合适大小
(x, y, w, h) = cv2.boundingRect(c)
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88))
# 每一个数字对应每一个模板
digits[i] = roi
然后进行匹配对象的图像处理:
1. 读入数据
2. 数据转换为灰度图
3. 使用礼帽操作
4. 使用腐蚀 或者 膨胀操作使图像中的主要信息部门连在一块,以便于后续取轮廓时能提取出主要信息 或者通过掩码的方式提取
5. 计算轮廓
6. 遍历轮廓
7. 得到矩形轮廓
8. 轮廓匹配
图像特征
图像特征:图像中能够区分物体的特殊像素点:边界 角点 关键点
1. 边界点: 图形中梯度值比较大的点
最大极值点,双阈值求值 -> 矩形边框
refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
2. 角点: 图形中拐角的点,通过角点检测方法。角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。
[任意方向的梯度值都很大可以视为角点]
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
cv2.cornerHarris()
img: 数据类型为 float32 的入图像
blockSize: 角点检测中指定区域的大小
ksize: Sobel求导中使用的窗口大小
k: 取值参数为 [0,04,0.06]
3.
.
: 通过图像尺度空间求出图像特征的关键点,即在一定范围内能够对同一个物体在不同尺度下有一个统一的认知,即能够识别出物体在不同尺度下都存在的表示特征的特点。
图像尺度空间的获取通常使用高斯模糊来实现。即通过一个高斯核函数进行图像矩阵变换,不同σ的高斯函数决定了对图像的平滑程度,越大的σ表示方差越大,对应的图像越模糊。
为了寻找DoG空间的极值点:首先建立图像尺度空间;然后每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于(或者小于)所有相邻点时,该点就是极值点。
中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较,求出局部极值点。然后通过局部极值点进行拟合,拟合成一个曲面,最后将这个曲面通过泰勒展开,求导求出真正的极值点(表示为特征点)
通过最大特征值和最小特征值得比例限制可以消除边界点的影响,当最大特征值和最小特征值的比例大于10时,即可认为是边界值,即可舍弃。
sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)
img = cv2.drawKeypoints(gray, kp, img)
4. 特征匹配
读取数据:
img1 = cv2.imread('box.png', 0)
img2 = cv2.imread('box_in_scene.png', 0)
特征关键点提取
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
这里的kps就是关键点。它所包含的信息有:
angle:角度,表示关键点的方向,通过Lowe大神的论文可以知道,为了保证方向不变形,SIFT算法通过对关键点周围邻域进行梯度运算,求得该点方向。-1为初值。
class_id:当要对图片进行分类时,我们可以用class_id对每个特征点进行区分,未设定时为-1,需要靠自己设定
octave:代表是从金字塔哪一层提取的得到的数据。
pt:关键点点的坐标
response:响应程度,代表该点强壮大小,更确切的说,是该点角点的程度。
size:该点直径的大小
一对一匹配:
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None,flags=2)
K对最佳匹配:
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good.append([m])
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
特征匹配流程:
1. 求出特征点
descriptor = cv2.xfeatures2d.SIFT_create()
(kpsA, featuresA) = self.detectAndDescribe(imageA)
(kpsB, featuresB) = self.detectAndDescribe(imageB)
2. 通过RANSAC算法进行特征匹配,并计算出从特征的ptsA状态 转变为ptsB状态的旋转矩阵
(H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)
3. 利用旋转矩阵进行图像旋转处理
result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
4. 图像拼接:
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
计算从A到B矩阵变换的变换矩阵
M = cv2.getPerspectiveTransform(A, B)
根据变换矩阵进行透视变换
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
openCV 背景建模
背景建模:用于判断视屏中动态背景和静态背景,由于场景中的目标在运动,目标的影像在不同图像帧中的位置不同。
该类算法对时间上连续的两帧图像进行差分运算,不同帧对应的像素点相减,判断灰度差的绝对值,当绝对值超过一定阈值时,
即可判断为运动目标,从而实现目标的检测功能。背景模型区分动态模型 静态模型的方法如下:
帧差法:对于较相机拍摄速度而言低速移动的物体,使用帧差法,即后一帧图像数据 减去 前一帧图像数据(帧差法)
混合高斯模型:在前景检测之前,先对背景进行训练,对图像背景中的每一种物体采用混合高斯模型的方式进行模拟训练,每一个背景的混合高斯模型。然后在测试阶段的像素进行GMM匹配,
如果该像素值能够匹配其中一个高斯,则认为是背景,否则认为是前景。由于整个过程GMM模型在不断更新学习中,所以对动态背景有一定的鲁棒性。最后通过对一个有树枝摇摆的动态背景进行前景检测,取得了较好的效果。
混合高斯模型学习方法
1.首先初始化每个高斯模型矩阵参数。
2.取视频中T帧数据图像用来训练高斯混合模型。来了第一个像素之后用它来当做第一个高斯分布。
3.当后面来的像素值时,与前面已有的高斯的均值比较,如果该像素点的值与其模型均值差在3倍的方差内,则属于该分布,并对其进行参数更新。
4.如果下一次来的像素不满足当前高斯分布,用它来创建一个新的高斯分布。
混合高斯模型测试方法
在测试阶段,对新来像素点的值与混合高斯模型中的每一个均值进行比较,如果其差值在2倍的方差之间的话,则认为是背景,否则认为是前景。将前景赋值为255,背景赋值为0。这样就形成了一副前景二值图。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) #指定形态学操作的核函数
fgbg = cv2.createBackgroundSubtractorMOG2() #创建高斯混合模型
ret, frame = cap.read() #数据读取
fgmask = fgbg.apply(frame) #高斯模型测试 得到训练的掩码
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) #开运算进行,去掉噪音
openCV 光流估计
光流估计
光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。
亮度恒定:同一点随着时间的变化,其亮度不会发生改变。
小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
空间一致:一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。
获取第一帧图像
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
获取跟踪的特征点(角点)
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
拿到第二帧图像
ret,frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
需要传入前一帧和当前图像以及前一帧检测到的角点进行跟踪
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
openCV 人脸关键点检测
人脸关键点检测:5 68个关键点,关键点是检测人的面部主要特征的边界进行一个像素点索引,