参考:https://www.bilibili.com/video/BV1PV411774y
harris角点检测
角点:沿着x,y图像灰度变化迅速
边界:沿着x轴,y轴,一个变化平稳,一个变化迅速
基本数学原理
判断平移前后自相似性
求解化简
特征归属划分
R接近0,平坦区域
小于0,边界
大于0,角点
1.计算梯度大小
2.合成矩阵,求特征值
3.比较特征值大小
opencv角点检测:
import cv2
import numpy as np
img = cv2.imread(r'./files/chessboard.jpg')
print ('img.shape:',img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
print ('dst.shape:',dst.shape)
img[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
SIFT(平移不变性特征转换)
图像尺度空间
让机器对物体不同尺度下有一个统一尺度,考虑图像在不同尺度下存在的特点。
1.高斯模糊
2.高斯差分金字塔
差异性结果:
3.特征关键点金字塔
关键点的精确定位
求导: -5/2-x=0,再算极值点
消除边界响应:
一个特征值大,一个特征值小,是边界
特征点的主方向
4.生成特征描述
5.特征向量生成
6.sift函数使用
3.4.2版本一下
import cv2
import numpy as np
img = cv2.imread('test_1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 得到特征点
sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)
img = cv2.drawKeypoints(gray, kp, img)
# 计算特征向量
kp, des = sift.compute(gray, kp)
特征匹配
BFMatcher蛮力匹配
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
watermarked_gb_img = cv2.imread('bg.png', 0)
watermarked = cv2.imread('target.png', 0)
zhihuwatermask = cv2.cvtColor(watermarked, cv2.COLOR_BGR2GRAY)
zhihuoutput = cv2.inpaint(zhihuimage, watermarked,3, flags= cv2.INPAINT_NS)
cv2.imshow('Result', thresh)
cv2.waitKey(0) ```
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
# crossCheck表示两个特征点要互相匹,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是
#NORM_L2: 归一化数组的(欧几里德距离),如果其他特征计算方法需要考虑不同的匹配计算方式
bf = cv2.BFMatcher(crossCheck=True)
一对一匹配
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)
过滤
随机抽样一致算法RANSAC
图像拼接方法
单应性矩阵
背景建模
帧差法(不常用)
对连续两帧图像进行差分运算,不同帧对应的像素点相减,判断绝对值,绝对值超过一定阙值时,即可判断为运动目标
缺点,会引入噪音和空洞问题
混合高斯模型
前景检测前,先对背景进行训练,采用混合高斯模型进行模拟,每个背景的混合高斯的个数可以自适应,然后在测试阶段对新的像素进行GMM匹配,如果该像素能匹配其中一个高斯,则认为是背景,否则认为是前景。
前景检测算法 (GMM),不断更新学习,对动态背景robust,最终通过对各一个有数值摇摆的动态背景进行前景检测,取得了较好的效果
混合高斯模型学习方法:
1.首先初始化每个高斯模型矩阵参数。
2.取视频中T帧数据图像用来训练高斯混合模型。来了第一个像素之后用它来当做第一个高斯分布。
3.当后面来的像素值时,与前面已有的高斯的均值比较,如果该像素点的值与其模型均值差在3倍的方差内,则属于该分布,并对其进行参数更新。
4.如果下一次来的像素不满足当前高斯分布,用它来创建一个新的高斯分布。
混合高斯模型测试方法
在测试阶段,对新来像素点的值与混合高斯模型中的每一个均值进行比较, 如果其差值在2倍的方差之间的话,则认为是背景,否则认为是前景。将前景赋值为255.背量赋值为0。这样就形成了一副前景二值图。
import numpy as np
import cv2
cap = cv2.VideoCapture('files/test.avi')
#形态学操作需要使用
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
#创建混合高斯模型用于背景建模
fgbg = cv2.createBackgroundSubtractorMOG2()
while (1):
# get a frame
ret, frame = cap.read()
fgmask = fgbg.apply(frame)
#形态学开运算去噪音点
fgmask = cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)
#寻找视频中的轮廓
#im,contours,HIERARCHY = cv2.findContours(thresh, cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
contour,hierarchy = cv2.findContours(fgmask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for c in contour:
perimeter =cv2.arcLength(c,True)
if perimeter > 188:
#找到直矩角
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow('frame',frame)
cv2.imshow('fgmask',fgmask)
#慢
k = cv2.waitKey(150)& 0xff
#退出键
if k==27:
break
cap.release()
cv2.destroyAllWindows()
光流估计
光流是空间运动物体在观测成像平面.上的像素运动的“瞬时速度",根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪
- 亮度恒定:同一点随着时间的变化,其亮度不会发生改变。
- 小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
- 空间一致: 一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度 一致。 因为光流法基本方程约束只有一个,而要求x, y方向的速度,有两个末知变量。所以需要连立n多个方程求解(比如车灯)
Lucas-Kanade算法
空间一致
cv2.calcOpticalFlowPyrLK():
参数:
- prevImage 前一帧图像
- nextImage 当前帧图像
- prevPts 待跟踪的特征点向量
- winSize 搜索窗口的大小
- maxLevel 最大的金字塔层数
返回:
- nextPts 输出跟踪特征点向量
- status 特征点是否找到,找到的状态为1,未找到的状态为0
角点可逆,先进行角点检测
先传入角点,才能进行光流估计
import numpy as np
import cv2
cap = cv2.VideoCapture('test.avi')
# 角点检测所需参数
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7)
# lucas kanade参数
lk_params = dict( winSize = (15,15),
maxLevel = 2)
# 随机颜色条
color = np.random.randint(0,255,(100,3))
# 拿到第一帧图像
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# 返回所有检测特征点,需要输入图像,角点最大数量(效率),品质因子(特征值越大的越好,来筛选)
# 距离相当于这区间有比这个角点强的,就不要这个弱的了
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# 创建一个mask
mask = np.zeros_like(old_frame)
while(True):
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)
# st=1表示
good_new = p1[st==1]
good_old = p0[st==1]
# 绘制轨迹
for i,(new,old) in enumerate(zip(good_new,good_old)):
a,b = new.ravel()
c,d = old.ravel()
mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
img = cv2.add(frame,mask)
cv2.imshow('frame',img)
k = cv2.waitKey(150) & 0xff
if k == 27:
break
# 更新
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()