import cv2
import numpy as np
#特征点匹配
def FeatureMatch(des1,des2):
ratio = 0.05
# K近邻算法求取在空间中距离最近的K个数据点,并将这些数据点归为一类
matcher = cv2.BFMatcher()
raw_matches = matcher.knnMatch(des1, des2, k = 2)
good_matches = []
for m1, m2 in raw_matches:
# 如果最接近和次接近的比值大于一个既定的值,那么我们保留这个最接近的值,认为它和其匹配的点为good_match
if m1.distance < ratio * m2.distance:
good_matches.append(m1)
return good_matches
def OpticalFlow():
# 打开usb摄像头,或者读取视频文件,一样
cap = cv2.VideoCapture("1.mp4")
# sift特征检测器
sift = cv2.SIFT_create(nfeatures=500, contrastThreshold=0.1, edgeThreshold=50, sigma=1.0)
lk_params = dict(winSize=(13, 13), # lucas kanade参数:搜索窗口、金字塔层数
maxLevel=3,
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
color = np.random.randint(0, 255, (1000, 3)) # 随机颜色条
# 拿到第一帧图像并灰度化作为前一帧图片
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# 利用opencv进行提取roi区域
x,y,w,h = cv2.selectROI("roi",old_frame)
roi = old_frame[y:y+h,x:x+w].copy()
# 查找roi区域特征
kp1, des1 = sift.detectAndCompute(roi, None)
# 检测全局特征点
kp3, des3 = sift.detectAndCompute(old_frame, None)
# 特征匹配
good_matches = FeatureMatch(des1,des3)
# 解析匹配点
p0 = []
for mc in good_matches:
p0.append( [[kp3[mc.trainIdx].pt[0], kp3[mc.trainIdx].pt[1]]] )
p0 = np.array(p0).astype(np.float32)
# 创建一个mask, 用于进行横线的绘制
mask = np.zeros_like(old_frame)
# 保存视频
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter('output.mp4',fourcc,20.0,(old_frame.shape[1] ,old_frame.shape[0]),True) # 黑白为false,彩色为True
while True:
# 读取图片灰度化作为后一张图片的输入
ret, frame = cap.read()
if ret == False:
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 进行金字塔LK光流检测需要输入前一帧和当前图像及前一帧检测到的特征点
pl, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
if len(pl[st == 1]) <= 1:
break
# 清除错误率太高的点
if max(err)>10:
plb = []
for p,e in zip(pl,err):
if e<10:
plb.append(p)
pl = np.array(plb)
if len(pl) <= 1:
break
# 读取运动了的角点st == 1表示检测到的运动物体,即v和u表示为0
good_new = pl
# 绘制轨迹
for i, (new, old) in enumerate(zip(good_new, p0)):
a, b = new.ravel().astype(int)
c, d = old.ravel().astype(int)
mask = cv2.line(mask, (a, b), (c, d), color[0].tolist(), 2)
frame = cv2.circle(frame, (a, b), 5, color[1].tolist(), -1)
#质心
center = np.mean(p0, axis=0).astype(np.int32)[0]
frame = cv2.circle(frame, (center[0], center[1]), 5, [255,0,0], -1)
# 外接矩形
x,y,w,h = cv2.boundingRect(p0)
# 画出运动物体的轮廓
frame = cv2.rectangle(frame, (x, y), (x + w, y + h), [0,0,255], 2)
# 叠加mask
img = cv2.add(frame, mask)
cv2.imshow('frame', img)
out.write(img)
k = cv2.waitKey(50) & 0xff
if k == 27:
break
# 第十步:更新前一帧图片和角点的位置
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
cv2.destroyAllWindows()
cap.release()
out.release()
if __name__ == '__main__':
OpticalFlow()
- 1
- 2
- 3
前往页