当前位置: 代码迷 >> 综合 >> 1.2 【YoloV3--tensorflow】Part two ---- Ubuntu16.04:opencv调用yolov3训练后的模型进行目标检测
  详细解决方案

1.2 【YoloV3--tensorflow】Part two ---- Ubuntu16.04:opencv调用yolov3训练后的模型进行目标检测

热度:17   发布时间:2023-12-23 13:16:59.0

一、首先将之前有关yolov3训练得到的模型文件以及模型配置文件和分类文件保存到新建的python工程文件夹目录下。也就是

yolov3-voc_3000.weights(模型权重文件)yolov3-voc.cfg(模型配置文件)voc.names(模型类别标签文件)。

二、代码详解

LABELS = open(labelsPath).read().strip().split("\n")

从模型分类标签当中得到数据集的类别,保存在列表当中。

In[6]: open(labelsPath).read()
Out[6]: 'cube\ncubiod\nhexagonal\ntriangular\n'
In[7]: open(labelsPath).read().strip()
Out[7]: 'cube\ncubiod\nhexagonal\ntriangular'
In[8]: open(labelsPath).read().strip().split('\n')
Out[8]: ['cube', 'cubiod', 'hexagonal', 'triangular']

声明三个数组:boxes 存放矩形框信息;confidences 存放框的置信度;classIDs 存放框的类别标签

三个数组元素一一对应,即boxes[0]、confidences[0]、classIDs[0]对应一个识别目标的信息,后期根据该信息在图片中画出识别目标的矩形框.

#加载 网络配置与训练的权重文件 构建网络
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)

需要至少opencv3及以上,opencv2中不支持dnn

#读入待检测的图像
image = cv2.imread('/home/darknet/scripts/VOCdevkit/VOC2019/JPEGImages/000770.jpg')
#得到图像的高和宽
(H,W) = image.shape[0:2]

然后得到yolo的输出层

ln = net.getLayerNames()
out = net.getUnconnectedOutLayers()
#得到未连接层得序号  [[200] /n  [227]  /n [254] ]
x = []
for i in out:   # 1=[200]x.append(ln[i[0]-1])    
# i[0]-1    取out中的数字  [200][0]=200  ln[199]= 'yolo_82'
ln=x

#从输入图像构造一个blob,然后通过加载的模型,给我们提供边界框和相关概率
#blobFromImage(image, scalefactor=None, size=None, mean=None, swapRB=None, crop=None, ddepth=None)
blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416),  swapRB=True, crop=False)#构造了一个blob图像,对原图像进行了图像的归一化 1 / 255.0,缩放尺寸 ,并对应训练模型时cfg的文件。

net.setInput(blob) #将blob设为输入??? 具体作用还不是很清楚
layerOutputs = net.forward(ln)  #ln此时为输出层名称,向前传播  得到检测结果

在检测结果中会有很多每个类的置信度为0的矩形框,因此要把这些与置信度较低的框去掉。

for output in layerOutputs:  #对三个输出层 循环for detection in output:  #对每个输出层中的每个检测框循环scores=detection[5:]  #detection=[x,y,h,w,c,class1,class2] scores取第6位至最后classID = np.argmax(scores)#np.argmax反馈最大值的索引confidence = scores[classID]if confidence >0.5:#过滤掉那些置信度较小的检测结果box = detection[0:4] * np.array([W, H, W, H])#print(box)(centerX, centerY, width, height)= box.astype("int")# 边框的左上角x = int(centerX - (width / 2))y = int(centerY - (height / 2))# 更新检测出来的框boxes.append([x, y, int(width), int(height)])confidences.append(float(confidence))classIDs.append(classID)

接下来进行非极大值抑制的操作,这一操作的目的是过滤掉同一物体上的多个矩形框,opencv的dnn有个直接的函数
NMSBoxes(bboxes, scores, score_threshold, nms_threshold, eta=None, top_k=None)
bboxes需要操作的各矩形框对应程序的boxes
scores矩形框对应的置信度对应程序的confidences
score_threshold置信度的阈值,低于这个阈值的框直接删除
nms_threshold nms的阈值
下面简单说下非极大值抑制的原理
1)先对输入检测框按置信度由高到低排序
2)挑选第一个检测框(即最高置信度,记为A)和其它检测框(记为B)进行iou计算

关于IOU的解释看这里
3)如果iou大于nmsThreshold, 那就将B清除掉
4)跳转到2)从剩余得框集里面找置信度最大得框和其它框分别计算iou
5)直到所有框都过滤完
NMSBoxes()函数返回值为最终剩下的按置信度由高到低的矩形框的序列号

附上完整代码

#coding:utf-8
import numpy as np
import cv2
import osweightsPath='yolov3-voc_3000.weights'# 模型权重文件
configPath="yolov3-voc.cfg"# 模型配置文件
labelsPath = "voc.names"# 模型类别标签文件#初始化一些参数
LABELS = open(labelsPath).read().strip().split("\n")
COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8")  # 随机生成颜色框boxes = []
confidences = []
classIDs = []#加载 网络配置与训练的权重文件 构建网络
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)#读入待检测的图像
image = cv2.imread('/home/jinyang/darknet/scripts/VOCdevkit/VOC2019/JPEGImages/000770.jpg')
#得到图像的高和宽
(H,W) = image.shape[0:2]# 得到 YOLO需要的输出层
ln = net.getLayerNames()
out = net.getUnconnectedOutLayers()#得到未连接层得序号  [[200] /n [267]  /n [400] ]
x = []
for i in out:   # 1=[200]x.append(ln[i[0]-1])    # i[0]-1    取out中的数字  [200][0]=200  ln(199)= 'yolo_82'
ln=x
# ln  =  ['yolo_82', 'yolo_94', 'yolo_106']  得到 YOLO需要的输出层#从输入图像构造一个blob,然后通过加载的模型,给我们提供边界框和相关概率
#blobFromImage(image, scalefactor=None, size=None, mean=None, swapRB=None, crop=None, ddepth=None)
blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416),  swapRB=True, crop=False)#构造了一个blob图像,对原图像进行了图像的归一化,缩放了尺寸 ,对应训练模型
net.setInput(blob) #将blob设为输入??? 具体作用还不是很清楚
layerOutputs = net.forward(ln)  #ln此时为输出层名称  ,向前传播  得到检测结果for output in layerOutputs:  #对三个输出层 循环for detection in output:  #对每个输出层中的每个检测框循环scores=detection[5:]  #detection=[x,y,h,w,c,class1,class2] scores取第6位至最后classID = np.argmax(scores)#np.argmax反馈最大值的索引confidence = scores[classID]if confidence >0.5:#过滤掉那些置信度较小的检测结果box = detection[0:4] * np.array([W, H, W, H])#print(box)(centerX, centerY, width, height)= box.astype("int")# 边框的左上角x = int(centerX - (width / 2))y = int(centerY - (height / 2))# 更新检测出来的框boxes.append([x, y, int(width), int(height)])confidences.append(float(confidence))classIDs.append(classID)idxs=cv2.dnn.NMSBoxes(boxes, confidences, 0.2,0.3)
box_seq = idxs.flatten()#[ 2  9  7 10  6  5  4]if len(idxs)>0:for seq in box_seq:(x, y) = (boxes[seq][0], boxes[seq][1])  # 框左上角(w, h) = (boxes[seq][2], boxes[seq][3])  # 框宽高color = COLORS[classIDs[seq]].tolist()cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)  # 画框text = "{}: {:.4f}".format(LABELS[classIDs[seq]], confidences[seq])cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_TRIPLEX, 1, color, 2)  # 写字
cv2.namedWindow('Image', cv2.WINDOW_NORMAL)
cv2.imshow("Image", image)
cv2.waitKey(0)


问题:在运行代码后倘若出现以下这样的错误,则说明模型配置文件有问题,需要将配置文件作以下修改,即将cfg配置文件中的前四行全部屏蔽即可。

#Testing
#batch=1
#subdivisions=1
#Training
batch=64
subdivisions=16

 net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)
cv2.error: OpenCV(3.4.4) /io/opencv/modules/dnn/src/darknet/darknet_io.cpp:507: error: (-215:Assertion failed) separator_index < line.size() in function 'ReadDarknetFromCfgStream'

上述代码亲测可行,如有问题请留言,欢迎各位bloger共同探讨学习。

本篇博客参考

opencv调用yolov3模型进行目标检测,以实例进行代码详解_月照银海似蛟龙的博客-CSDN博客_opencv调用yolov3

其他关于opencv调用yolo模型进行检测的博客归纳如下:

OpenCV+yolov3实现目标检测(C++,Python)_pan_jinquan的博客-CSDN博客_c++实现目标检测

YOLOV3实战3:用python调用Darknet接口处理视频_phinoo的博客-CSDN博客_darknet python

基于OpenCV和YOLOv3深度学习的目标检测_qq_27158179的博客-CSDN博客_yolov3目标检测

  相关解决方案