# 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)
