在目标检测研究领域,基于深度学习模型的方法效果要比传统的特征检测方法好很多。传统的如基于harr特征、hog特征等速度很快,但精度总是不是很理想。基于深度网络的智能算法包括两步法和一步法。两步法模型包括R-CNN、Fast R-CNN等,一步法模型包括yolo系列和ssd等。下面基于opencv提供的DNN深度神经模块,结合开源的yolo系列的yolov4实现目标检测。
HOG特征是计算方向梯度直方图得到的高维向量,可用于描述图像的局部纹理特征。它的基本思想是:将一副图像划分为小的单元cell,尺寸为8*8的cell,统计这8*8个cell内的方向梯度直方图,然后将4个cell构成一个block块,将这个block块内所有的cell内的hog descriptor特征串联起来就可以得到这个block的HOG特征。最后将每个block的HOG特征串联起来形成整个图像的HOG特征。
如下为基于HOG特征来实现行人检测的代码:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
#判断框与框重叠的情况
def is_inside(o, i):
ox, oy, ow, oh = o
ix, iy, iw, ih = i
return ox > ix and oy > iy and ox + ow < ix + iw and oy + oh < iy + ih
#输入检测图像
img = cv2.imread("1.jpg")
#创建hog算子
hog = cv2.HOGDescriptor()
#设置svm分类器
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
#基于hog算子对整个图像开展检测
found, w = hog.detectMultiScale(img, winStride=(8, 8), scale=1.05)
#对检测到的图像box进行重合去除处理
found_filtered = []
for ri, r in enumerate(found):
for qi, q in enumerate(found):
if ri != qi and is_inside(r, q):
break
else:
found_filtered.append(r)
#对box中的行人进行标注
for person in found_filtered:
x, y, w, h = person
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 255), 2)
#显示检测图像
cv2.imshow("people detection", img)
cv2.waitKey(0)
运行后得到的结果如下:
这种结果还是不错的,但遇到目标较多时就会出现问题,下图看到中间两个行人就落在一个框内了。
2. 基于yolov4实现目标检测
yolo框架系列在图像目标检测里应用还是非常多的,框架系列从yolov1,v2,v3,v4以及到今年6月份发布的v5。yolov4属于网络调优集大成结果,通过多种方式改善原有框架的性能,包括在backbone特征提取部分、neck特征增强部分以及head部分进行了许多优化,最终在fps和ap方面比yolov3性能都要好。我们先来实践,后面再慢慢理解其原理。
整个过程分为几步:
第一步,下载yolov4框架的配置文件和权值模型,以及coco.names类别。
这三个文件名为:yolov4.cfg,yolov4.weights,coco.names。因为都是开源的,可以直接从github上下载。地址为:
Build software better, togethergithub.com第二步,基于opencv的dnn模块加入yolov4配置文件实现网络模型创建
net = cv.dnn_DetectionModel('yolov4.cfg', 'yolov4.weights')
net.setInputSize(320, 320)
net.setInputScale(1.0 / 255)
net.setInputSwapRB(True)
第三步,读取coco.names文件的类别形成列表
with open('coco.names', 'rt') as f:
names = f.read().rstrip('n').split('n')
第四步,读入新的图像基于模型net对象的detect方法开展检测处理
frame = cv.imread("1.jpg")
classes, confidences, boxes = net.detect(frame, confThreshold=0.1, nmsThreshold=0.4)
detect方法的参数解释如下:
frame: 图像; confThreshold: 用于根据置信度筛选框的阈值; nmsThreshold: 非最大抑制中使用的阈值。
处理之后返回:
[out] classes 结果检测中的类索引。
[out] confidences 一组相应的置信度。
[out] boxes 一组边界框。
第五步,设置置信度阈值筛选满足条件的目标,对目标进行标注。
or classId, confidence, box in zip(classes.flatten(), confidences.flatten(), boxes):
if confidence>threshold:
left, top, w, h = box
cv.rectangle(frame, box, color=(0, 255, 0), thickness=3)
cv.rectangle(frame, (left, top), (left + w, top + h), (255, 255, 255), cv.FILLED)
cv.putText(frame, labels[classId], (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))
第六步,查看最终输出结果
cv.imshow('out', frame)
cv.waitKey(0)
最终输出结果为:
可以看出,同一张图,采用hog特征以及svm分类器识别的内容和基于yolov4模型检测到的目标差别太多了。基于yolov4模型对手提袋都检测出来了。当然coco.names类别也有限,所以图中的某些目标也是没有标注出来的。
最后给出整个识别过程的源代码:
# -*- coding: utf-8 -*-
import cv2 as cv
import time
#创建模型net
net = cv.dnn_DetectionModel('yolov4.cfg', 'yolov4.weights')
net.setInputSize(320, 320)
net.setInputScale(1.0 / 255)
net.setInputSwapRB(True)
#创建类别names
with open('coco.names', 'rt') as f:
names = f.read().rstrip('n').split('n')
#读入图像开展目标检测处理
frame = cv.imread('2.jpg')
classes, confidences, boxes = net.detect(frame, confThreshold=0.1, nmsThreshold=0.4)
#对识别目标进行标注
for classId, confidence, box in zip(classes.flatten(), confidences.flatten(), boxes):
if confidence>0.5:
left, top, w, h = box
cv.rectangle(frame, (left, top), (left + w, top + h), (0,255,0),2 )
cv.putText(frame, names[classId], (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))
cv.imshow('out', frame)
cv.waitKey(0)