1. Mobilenet 介绍
Mobilenet 是一种专为移动和嵌入式视觉应用而设计的卷积神经网络。它们不使用标准的卷积层,而是基于使用深度可分离卷积的简化架构,使用这种架构,我们可以为移动和嵌入式设备(例如:树莓派)构建低延迟的轻量级深度神经网络。
2. SSD运动目标检测算法介绍
SSD(single Shot Multi Box Detection)是一种针对多种类别的单次深度神经网络,同时集中了 YOLO 的回归思想和 Faster RCNN 算法的 Anchor 机制,从一个层面来说,采用回归思想可以降低检测过程中卷积计算的复杂度,使得算法时效性整体提高,从另一层面来说,采用 Anchors机制能够提取不同宽、高比例的特征,提高算法的鲁棒性,在识别方面,该算法比YOLO 算法在对某一位置进行全局特征提取时效果更好,因此,SSD 算法的核心思想是基于小卷积滤波器来预测目标,并生成一组固定的默认边界框,并给出类别得分和偏移,这样设计的好处在于,当检测不规则大小形状的物体时鲁棒性增强。
SSD (Single Shot MultiBox Detector)是一种流行的物体检测算法。SSD 通过消除对区域生成网络的需求来加速该过程。为了防止精度下降,SSD采用了包括多尺度功能和默认框在内的一些改进方法。这些改进使 SSD 能够以较低分辨率的图像匹配更快的R-CNN精度,从而进一步提高检测速度。带有MobileNet的SSD是一种针对移动设备推理进行了优化的对象检测模型。
这里的关键思想是采用单个网络(速度)而不需要区域提议。相反,它使用不同的边界框,然后作为预测的一部分调整边界框。网络的最后几层中的每一层都负责预测逐渐变小的边界框,并且最终预测是所有这些预测的并集,从而实现不同的边界框预测。
3. OpenCV DNN 模块 MobileNet-SSD 介绍
OpenCV DNN 模块支持常见的对象检测模型SSD,以及它的移动版Mobile Net-SSD,特别是后者在端侧边缘设备上可以实时计算,基于Caffe训练好的 mobile-net SSD支持20类别对象检测。
在Caffe训练好的 mobile-net SSD 中内置了“background","aeroplane”,"bicycle","bird", "boat","bottle","bus","horse","motorbike","car","cat","chair","person","pottedplant", "sheep","cow","diningtable"," dog"等20种对象检测。
4.源程序代码
运行程序后,该程序实现了两个 SSD 目标检测实验
4.1 提前录制的视频目标识别
在网络上下载提前录制好的视频文件,可以看到如下流程的检测各种车辆的识别效果。
# 载入必要的库
import cv2
# 线程函数操作库
import threading # 线程
import ctypes
import inspect
# 线程结束代码
def _async_raise(tid, exctype):
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
def bgr8_to_jpeg(value, quality=75):
return bytes(cv2.imencode('.jpg', value)[1])
import traitlets
import ipywidgets.widgets as widgets
from IPython.display import display
detection_img = widgets.Image(format='jpeg', width=1920, height=1080)
display(detection_img)
config_file = 'ssd_mobilenet_v3_large_coco_2020_01_14.pbtxt'
frozen_model = 'frozen_inference_graph.pb'
model = cv2.dnn_DetectionModel(frozen_model, config_file)
classLabels = []
filename = 'labels.txt'
with open(filename, 'rt') as spt:
classLabels = spt.read().rstrip('\n').split('\n')
model.setInputSize(320, 320) #greater this value better the reults but slower. Tune it for best results
model.setInputScale(1.0/127.5)
model.setInputMean((127.5, 127.5, 127.5))
model.setInputSwapRB(True)
cap = cv2.VideoCapture('test_video.mp4')
ret, frame = cap.read()
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video = cv2.VideoWriter('video.avi', fourcc, 25, (frame.shape[1], frame.shape[0])) #25 is the frame rate of output video you can change it as required
font = cv2.FONT_HERSHEY_PLAIN
def Video_display():
while(True):
ret, frame = cap.read()
classIndex, confidence, bbox = model.detect(frame , confThreshold=0.65) #tune the confidence as required
if(len(classIndex) != 0):
for classInd, boxes in zip(classIndex.flatten(), bbox):
cv2.rectangle(frame, boxes, (255, 0, 0), 2)
cv2.putText(frame, classLabels[classInd-1], (boxes[0] + 10, boxes[1] + 40), font, fontScale = 1, color=(0, 255, 0), thickness=2)
video.write(frame)
detection_img.value = bgr8_to_jpeg(frame) # 实时显示图像
# 开始线程
t = threading.Thread(target=Video_display)
t.setDaemon(True)
t.start()
# 结束线程
stop_thread(t)
4.2 摄像头目标识别
import libcamera
from picamera2 import Picamera2
picamera = Picamera2()
config = picamera.create_preview_configuration(main={"format": 'RGB888', "size": (320, 240)},
raw={"format": "SRGGB12", "size": (1920, 1080)})
config["transform"] = libcamera.Transform(hflip=0, vflip=1)
picamera.configure(config)
picamera.start()
pidetection_img = widgets.Image(format='jpeg', width=640, height=480)
display(pidetection_img)
def PiVideo_display():
while(True):
frame = picamera.capture_array()
classIndex, confidence, bbox = model.detect(frame , confThreshold=0.65) #tune the confidence as required
if(len(classIndex) != 0):
for classInd, boxes in zip(classIndex.flatten(), bbox):
cv2.rectangle(frame, boxes, (255, 0, 0), 2)
cv2.putText(frame, classLabels[classInd-1], (boxes[0] + 10, boxes[1] + 40), font, fontScale = 1, color=(0, 255, 0), thickness=2)
video.write(frame)
pidetection_img.value = bgr8_to_jpeg(frame) # 实时显示图像
# 开始线程
t1 = threading.Thread(target=PiVideo_display)
t1.setDaemon(True)
t1.start()
# 结束线程
stop_thread(t1)