使用OpenCV和YOLO分别实现持刀检测(Python)
专注计算机视觉,分析底层原理。我们通过OpenCV和YOLO两种不同的技术实现对持刀检测的算法实现。
一、计算机视觉方法(OpenCV)
1. 底层原理
传统计算机视觉方法依赖于手工设计特征和规则来完成目标检测任务。对于“持刀”动作的检测,可以分为以下几个步骤:
背景减除 :分离前景(运动物体)和背景。
目标检测 :识别图像中的物体(如人和刀具)。
特征提取与匹配 :提取刀具的形状、纹理等特征,并判断其是否被手持。
动作分析 :通过时间序列分析,判断“持刀”的动作。
2. 技术过程
(1) 背景减除
使用背景减除算法(如MOG2或KNN)从视频帧中提取运动物体。这一步可以帮助我们关注场景中的动态部分(如人和刀具),忽略静态背景。
import cv2
cap = cv2.VideoCapture('video.mp4')
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, frame = cap.read()
if not ret:
break
fgmask = fgbg.apply(frame)
cv2.imshow('Foreground Mask', fgmask)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
(2) 目标检测
利用边缘检测(如Canny)或轮廓检测(cv2.findContours)找到可能的刀具区域。可以通过模板匹配或形状分析进一步确认刀具的存在。
edges = cv2.Canny(frame, 100, 200)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
if w > 50 and h > 10: # 假设刀具的长宽比符合一定条件
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
(3) 特征提取与匹配
使用HOG(Histogram of Oriented Gradients)提取刀具的形状特征。
使用SIFT或ORB算法进行特征匹配,验证检测到的物体是否为刀具。
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(template_image, None)
kp2, des2 = sift.detectAndCompute(frame, None)
bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
matches = bf.match(des1, des2)
(4) 动作分析
通过跟踪人体的关键点(如手部位置)和刀具的位置关系,判断是否发生了“持刀”动作。可以使用光流法(Optical Flow)跟踪刀具和手部的运动轨迹。
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
next_gray = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prev_gray, next_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
二、基于深度学习的方法(YOLO框架)
1. 底层原理
深度学习方法利用神经网络自动学习特征,避免了手工设计特征的复杂性。YOLO(You Only Look Once)是一种实时目标检测算法,适合处理视频中的动态场景。它将目标检测问题转化为回归问题,直接预测目标的类别和边界框。
2. 技术过程
(1) 数据准备
收集标注数据:需要大量包含“持刀”动作的视频或图像数据,并标注刀具和人体的关键部位(如手部)。
数据增强:对数据进行旋转、缩放、翻转等操作,提高模型的泛化能力。
(2) 模型训练
使用YOLOv5或YOLOv7框架进行训练。
定义自定义数据集格式(如YOLO格式的标签文件)。
修改配置文件,指定类别数(如“人”和“刀”)。
# 下载YOLOv5代码
git clone https://github.com/ultralytics/yolov5
cd yolov5
# 安装依赖
pip install -r requirements.txt
# 训练模型
python train.py --img 640 --batch 16 --epochs 50 --data custom_data.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt
(3) 推理与后处理
加载训练好的模型,对视频帧进行推理。
提取检测结果,筛选出“人”和“刀”的检测框。
判断刀具是否在人的手部附近,从而确认“持刀”动作。
import torch
from PIL import Image
# 加载模型
model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt')
# 推理
results = model(frame)
# 解析结果
detections = results.xyxy[0].numpy() # 获取检测框
for detection in detections:
x1, y1, x2, y2, conf, cls = detection
if cls == 0: # 假设0表示“人”,1表示“刀”
person_box = [x1, y1, x2, y2]
elif cls == 1:
knife_box = [x1, y1, x2, y2]
# 判断“持刀”动作
if person_box and knife_box:
if is_holding(person_box, knife_box): # 自定义函数判断刀具是否在手部附近
print("Detected holding a knife!")
(4) 动作分析
使用关键点检测模型(如OpenPose或MediaPipe)获取人体的手部位置。
结合刀具的检测框,判断刀具是否位于手部附近。
import mediapipe as mp
mp_hands = mp.solutions.hands.Hands()
results = mp_hands.process(frame_rgb)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
hand_x = hand_landmarks.landmark[mp.solutions.hands.HandLandmark.INDEX_FINGER_TIP].x
hand_y = hand_landmarks.landmark[mp.solutions.hands.HandLandmark.INDEX_FINGER_TIP].y
# 判断刀具是否靠近手部
三、总结
OpenCV适合简单场景,但对复杂背景和多变姿态的适应性较差。
YOLO具有更高的准确性和鲁棒性,但需要大量标注数据和计算资源。但当前有大量的公共数据集用来训练,所以比较好实现。
在实际应用中,我们的AI边缘计算盒子和AI门禁以及摄像头均加载了持刀检测算法,均用YOLO检测持刀行为。