| name | video-analysis |
| description | OpenCV4 视频分析技能 - 视频读取/保存、光流、背景分离、帧差分、运动检测 |
| user-invocable | true |
| argument-hint | 视频分析 OR 光流 OR 背景分离 OR 运动检测 OR 视频处理 |
OpenCV4 Video Analysis Skill
视频分析完整指南
何时使用
当需要以下帮助时使用此技能:
- 视频读取和保存
- 光流估计(稀疏/稠密)
- 背景分离和前景检测
- 帧差分和运动检测
- 物体追踪
- 视频稳定化
快速参考
视频读取和保存
import cv2
cap = cv2.VideoCapture('video.mp4')
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, 30.0, (w, h))
out.write(frame)
out.release()
fps = cap.get(cv2.CAP_PROP_FPS)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
光流(稠密)
import cv2
import numpy as np
cap = cv2.VideoCapture('video.mp4')
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(old_gray, maxCorners=100,
qualityLevel=0.3, minDistance=7)
corners = np.int0(corners)
lk_params = dict(winSize=(21, 21), maxLevel=3,
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 30, 0.01))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
new_corners, status, _ = cv2.calcOpticalFlowPyrLK(
old_gray, frame_gray, corners, None, **lk_params)
good_old = corners[status.flatten() == 1]
good_new = new_corners[status.flatten() == 1]
for new, old in zip(good_new, good_old):
a, b = new.ravel()
c, d = old.ravel()
cv2.line(frame, (a, b), (c, d), (0, 255, 0), 2)
cv2.circle(frame, (a, b), 5, (0, 0, 255), -1)
cv2.imshow('Optical Flow', frame)
if cv2.waitKey(1) & 0xFF == ():
old_gray = frame_gray.copy()
corners = good_new.reshape(-, , )
cap.release()
cv2.destroyAllWindows()
稠密光流(Farneback)
prev = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
next = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prev, next, None,
0.5, 3, 15, 3, 5, 1.2, 0)
h, w = frame.shape[:2]
hsv = cv2.createTrackbar('Hue', 'flow', 0, 179, lambda x: None)
flow_hsv = np.zeros_like(frame)
flow_hsv[..., 1] = 255
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
flow_hsv[..., 0] = ang * 180 / np.pi / 2
flow_hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
flow_bgr = cv2.cvtColor(flow_hsv, cv2.COLOR_HSV2BGR)
背景分离
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
fgmask = fgbg.apply(frame)
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Foreground', fgmask)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
帧差分
ret, frame1 = cap.read()
ret, frame2 = cap.read()
while cap.isOpened():
ret, frame3 = cap.read()
if not ret:
break
diff1 = cv2.absdiff(frame2, frame1)
diff2 = cv2.absdiff(frame3, frame2)
diff = cv2.bitwise_and(diff1, diff2)
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 25, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
if cv2.contourArea(contour) > 500:
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(frame3, (x, y), (x+w, y+h), (0, 255, 0), 2)
frame1 = frame2
frame2 = frame3
cap.release()
C++ 实现
#include <opencv2/opencv.hpp>
#include <opencv2/video.hpp>
#include <opencv2/videoio.hpp>
using namespace cv;
Ptr<BackgroundSubtractor> pBackSub = createBackgroundSubtractorMOG2(500, 16, true);
Mat fgMask, frame;
while (capture.read(frame)) {
pBackSub->apply(frame, fgMask);
imshow("Foreground", fgMask);
if (waitKey(30) == 'q') break;
}
vector<Point2f> corners, newCorners;
goodFeaturesToTrack(prevGray, corners, 100, 0.3, 7);
calcOpticalFlowPyrLK(prevGray, currGray, corners, newCorners, status, err, Size(21,21), 3);
最佳实践
-
光流选择:
- 稀疏光流:实时性要求高、只需要关键点
- 稠密光流:需要完整运动信息
-
背景分离器选择:
- MOG2:复杂场景、需检测阴影
- KNN:简单场景、更快
- GMG:动态背景变化
-
运动检测:
- 三帧差分比两帧差分更稳定
- 结合形态学操作消除噪声
- 最小轮廓面积过滤
-
视频稳定化:
相关技能