# coding:utf-8 import cv2 import argparseimport numpy as np parser = argparse.ArgumentParser(description='manual to this script') parser.add_argument("--videoOrImage", default=0) args = parser.parse_args() '''初始化参数''' confThreshold = 0.25 # 置信度,忽略掉低于置信度阈值参数的所有框 nmsThreshold = 0.4 # 非极大抑制参数,对其余框执行非极大值抑制,这会消除多余的重叠边界框 inpWidth = 416 inpHeight = 416 modelConfiguration = r"C:\Users\Administrator\Desktop\darknet\cfg\yolov3.cfg"; modelWeights = r'C:\Users\Administrator\Desktop\darknet_weights\yolov3.weights'; classesFile = r"C:\Users\Administrator\Desktop\darknet\data\coco.names"; classes = None ''' t是windows平台特有的所谓text mode(文本模式),区别在于会自动识别windows平台的换行符。类Unix平台的换行符是\n, 而windows平台用的是\r\n两个ASCII字符来表示换行,python内部采用的是\n来表示换行符。rt模式下,python在读取文本时会自动把\r\n转换成\n. ''' with open(classesFile, 'rt') as f: classes = f.read().rstrip('\n').split('\n') COLORS = np.random.randint(0, 255, size=(len(classes), 3), dtype='uint8') # 颜色 #加载 网络配置与训练的权重文件 构建网络 net = cv2.dnn.readNetFromDarknet(modelConfiguration, modelWeights) cap = cv2.VideoCapture(args.videoOrImage) cv2.namedWindow("win", cv2.WINDOW_NORMAL) while cv2.waitKey(1) < 0: res, frame = cap.read() if not res: break ''' 从输入图像或视频流中读取帧后,将通过 blobFromImage 函数将其转换为神经网络的输入blob。在此过程中, 它使用比例因子1/255 将图像像素值缩放到0到1的目标范围。它还将图像的大小缩放为给定的大小(416,416)而不进行裁剪。 请注意,我们不在此处执行任何均值减法,因此将[0,0,0]传递给函数的mean参数,并将swapRB参数保持为其默认值1。 ''' blob = cv2.dnn.blobFromImage(frame, 1/255.0, (inpWidth, inpHeight), [0, 0, 0], swapRB=1, crop=False) ''' 然后输出blob作为输入传递到网络,并运行前向传递以获得预测边界框列表作为网络的输出。这些框经过后处理步骤,以滤除具有低置信度分数的那些框。 ''' net.setInput(blob) ''' OpenCV 的 Net 类中的 forward 函数需要知道它的结束层。 想要遍历整个网络就需要识别网络的最后一层。 我们通过使用函数getUnconnectedOutLayers()来实现,该函数给出了未连接的输出层名称,这些输出层基本上是网络的最后一层。 然后我们运行网络的前向传递以从输出层获得输出 ''' layersNames = net.getLayerNames() # ['conv_0', 'bn_0', 'relu_0', 'conv_1', 'bn_1', .......] ''' net.getUnconnectedOutLayers():得到未连接层得序号 例如:[[200], [227]] i[0]-1 取out中的数字 [200][0]=200 layersNames(199)= 'yolo_82' ''' outs = net.forward([layersNames[i[0] - 1] for i in net.getUnconnectedOutLayers()]) # net.forward(['conv_0', 'bn_0'])得到了所有输出结果的输出 ''' 网络 outs 每个输出都由一组 类数目+5 个元素的向量表示。前4个元素代表center_x,center_y,width和height。 第五个元素表示边界框包围对象的置信度。其余元素是与每个类相关的置信度(即对象类型)。 该框被分配到与该框的最高分相对应的那一类。 ''' frameHeight = frame.shape[0] frameWidth = frame.shape[1] classIds = [] confidences = [] boxes = [] for out in outs: for detection in out: # detection的前五元素(中心坐标点以及长宽)[center_x,center_y,width,height,边界框包围对象的置信度,。。。。。。] scores = detection[5:] # 所有元素的置信度 classId = np.argmax(scores, axis=0) # 取出最大置信度所对应的索引 confidence = scores[classId] # g根据索引取出最大的置信度 if confidence > confThreshold: # 判断当前的置信度是否大于设定的阈值 center_x = int(detection[0] * frameWidth) center_y = int(detection[1] * frameHeight) width = int(detection[2] * frameWidth) height = int(detection[3] * frameHeight) left = int(center_x - width / 2) top = int(center_y - height / 2) classIds.append(classId) # 将最大置信度的索引也就是类别的索引加入集合 confidences.append(float(confidence)) # 将置信度加入集合 boxes.append([left, top, width, height]) # 将坐标左上和长宽加入box ''' 对其置信度等于或大于阈值的框进行非极大值抑制。 这将会减少重叠框的数量。 ''' indices = cv2.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold) for i in indices: i = i[0] box = boxes[i] left = box[0] top = box[1] width = box[2] height = box[3] color = [int(c) for c in COLORS[classIds[i]]] cv2.rectangle(frame, (left, top), (left + width, top + height), color, 2) text = "{}".format(classes[classIds[i]]) cv2.putText(frame, text, (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) cv2.imshow("win", frame)