YOLO Object Detection with OpenCV
生活随笔
收集整理的這篇文章主要介紹了
YOLO Object Detection with OpenCV
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- Object Detection with Image
- Object Detection with Video
? 這篇文章只是基于OpenCV使用YOLOv3算法執行目標檢測;不涉及到YOLOv3的理論原理、不涉及訓練過程;也就是說僅僅使用訓練好的模型文件基于OpenCV做測試;包括圖片和視頻;
? 只用作筆記,原教程地址:YOLO object detection with OpenCV
Object Detection with Image
# 執行方式 # 里面涉及到的文件,可以到原博客地址下載,或者contact me python yolo_cz.py --image images/baggage_claim.jpg --yolo yolo-coco #!/usr/bin/env python #-*- coding:utf-8 -*- # @Time : 19-4-23 下午4:36 # @Author : chen# 一些依賴包 import numpy as np import argparse import time import cv2 import os# 命令行參數解析 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to input image") ap.add_argument("-y", "--yolo", required=True, help="base path to YOLO directory") ap.add_argument("-c", "--confidence", type=float, default=0.5, help="minimum probability to filter weak detections") ap.add_argument("-t", "--threshold", type=float, default=0.3, help="threshold when applying non-maxima suppression") args = vars(ap.parse_args())# 加載COCO標簽,因為使用YOLOv3的權重文件是在COCO數據集上訓練得到的 labelsPath = os.path.sep.join([args["yolo"], "coco.names"]) LABELS = open(labelsPath).read().strip().split("\n")# 初始化一個80*3的數組,數組元素值介于0~255; # 80表示COOC總共有80個類別; # 每一行表示一個顏色值,用不同的顏色框出不同類別的物體 np.random.seed(42) COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype=np.uint8)# YOLOv3訓練好的權重文件路徑以及網絡配置文件路徑 weightsPath = os.path.sep.join([args["yolo"], "yolov3.weights"]) configPath = os.path.sep.join([args["yolo"], "yolov3.cfg"])# 加載網絡 # 因為權重文件是由Darknet訓練得到,使用cv2.dnn.readNetFromDarknet()加載 # opencv中也提供了其他網絡模型的加載方法,TensorFlow,Caffe... print("[INFO] loading YOLO from disk...") net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)# 讀取待檢測的圖片,并獲取其維度信息 image = cv2.imread(args["image"]) (H, W) = image.shape[:2]# 獲取輸出層的名稱: ['yolo_82', 'yolo_94', 'yolo_106'] ln = net.getLayerNames() ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()] """ 上面這兩句的目的是為了獲取輸出層的名字 什么意思呢? 先來看net.getLayerNames()與net.getUnconnectedOutLayers()的用法了: net.getLayerName()用法如其名:獲取每一層的名稱,返回一個列表,如:[conv_0, bn_0, relu_0, conv_1,..., permut_106, yolo_106] net.getUnconnectedOutLayers()也可以猜到部分含義:這里Unconnected就是后面沒有連接的層了;那么它的作用是以列表的形式返回輸出層在整個網絡中的索引位置; 上面兩行代碼含義也就明顯了:得到輸出是:['yolo_82', 'yolo_94', 'yolo_106']其實,還有一個函數,簡單明了,直接一步就得到想要的輸出了,就是: net.getUnconnectedOutLayerNames() """# 根據輸入圖像構造blob # 好像opencv讀取深度網絡模型,網絡的輸入都要轉換成blob的形式 blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416), swapRB=True, crop=False)# 輸入到網絡中,并執行前向傳播 net.setInput(blob) start = time.time() layerOutputs = net.forward(ln) end = time.time()# 輸出一次Inference所用時間 print("[INFO] YOLO took {:.6f} seconds.".format(end - start))""" layerOutsputs是YOLO算法在圖片中檢測到的bbx的信息 由于YOLO v3有三個輸出,也就是上面提到的['yolo_82', 'yolo_94', 'yolo_106'] 因此layerOutsputs是一個長度為3的列表 其中,列表中每一個元素的維度是(num_detection, 85) num_detections表示該層輸出檢測到bbx的個數 85:因為該模型在COCO數據集上訓練,[5:]表示類別概率;[0:4]表示bbx的位置信息;[5]表示置信度下面要做的就是對網絡輸出的bbx進行檢查: 判定每一個bbx的置信度是否足夠的高,以及執行NMS算法去除冗余的bbx """# 初始化列表,用以保存bbx的位置信息、類別有關的最大概率值以及對應的索引位置 boxes = [] confidences = [] classIDs = []# 對每個輸出層的輸出進行迭代 for output in layerOutputs:# 對每一個bbx進行檢測for detection in output:scores = detection[5:] # 各類別的概率classID = np.argmax(scores) # 最大概率位置索引confidence = scores[classID] # 最大概率# 判斷是否滿足人為設定的閾值if confidence > args["confidence"]:# 如果滿足,獲取bbx的坐標信息box = detection[0:4] * np.array([W, H, W, H])(centerX, centerY, width, height) = box.astype("int")# 計算bbx的坐標信息,bbx左上角點的坐標x = int(centerX - (width/2))y = int(centerY - (height/2))# 更新上面設置的幾個列表boxes.append([x, y, int(width), int(height)]) # 原博客中這樣寫,其實width、height已經是intconfidences.append(float(confidence))classIDs.append(classID)# 上面已經對三個輸出層檢測到bbx檢測完了 # 可以看出,人為設定一個閾值,如果檢測到類別概率最大值小于該閾值,則該bbx無效# 經過上一步保留下來的bbx的confidence都是大于人為設定的閾值 # 但是會出現冗余的bbx,即檢測到的bbx可以都是一個object # 所以會使用NMS算法去除重復的檢測框 # 有關NMS算法部分,請自行google idxs = cv2.dnn.NMSBoxes(boxes, confidences, args["confidence"], args["threshold"]) """ 那么idxs返回的是什么呢? idxs返回的是一個一維數組,其中數組的元素表示保留下來的bbx的索引位置 例如:執行NMS之前bbx有15個,即boxes是一個長度為15的列表idxs中的元素就表示經過NMS算法后,保留下來的bbx在boxes列表中的索引位置 """# 因此,下面就提取出最后bbx的位置信息, # 并利用OpenCV將其畫到圖片上if len(idxs) > 0:# 循環每一個bbxfor i in idxs.flatten():# bbx的坐標信息(x, y) = (boxes[i][0], boxes[i][1])(w, h) = (boxes[i][2], boxes[i][3])# 獲取當前bbx所對應的顏色值(還記得最一開始的COLORS嗎?就是一個類別對應一種顏色)# 顏色值需要根據classID來確定color = [int(c) for c in COLORS[classIDs[i]]]# 使用OpenCV畫矩形cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)# 需要顯示在圖片上的文本信息text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])cv2.putText(image, text, (x, y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)# 顯示圖片 cv2.imshow("Image", image) cv2.imwrite("output.jpg", image) cv2.waitKey(0)Object Detection with Video
# 執行方式 # 里面涉及到的文件,可以到原博客地址下載,或者contact me python yolo_video_cz.py --input videos/car_chase_01.mp4 --output output/chen.avi --yolo yolo-coco #!/usr/bin/env python #-*- coding:utf-8 -*- # @Time : 19-4-23 下午7:34 # @Author : chen""" 基于視頻的目標檢測的測試和上面基于圖像的目標檢測原理都是一樣的 不同的地方在于,需要從視頻中提取每一幀進行目標檢測 并將最終檢測的結果形成視頻保存代碼有許多相似之處,不再具體解釋"""# 加載依賴包 import numpy as np import argparse import imutils import time import cv2 import os# 解析命令行參數 ap = argparse.ArgumentParser() ap.add_argument("-i", "--input", required=True, help="path to input video") ap.add_argument("-o", "--output", required=True, help="path to output video") ap.add_argument("-y", "--yolo", required=True, help="base path to YOLO directory") ap.add_argument("-c", "--confidence", type=float, default=0.5, help="minimum probability to filter weak detections") ap.add_argument("-t", "--threshold", type=float, default=0.3, help="threshold when applyong non-maxima suppression") args = vars(ap.parse_args())# 加載COCO數據集標簽 labelsPath = os.path.sep.join([args["yolo"], "coco.names"]) LABELS = open(labelsPath).read().strip().split("\n")# 獲取顏色值 np.random.seed(42) COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8")# 加載YOLO目標檢測器 weightsPath = os.path.sep.join([args["yolo"], "yolov3.weights"]) configPath = os.path.sep.join([args["yolo"], "yolov3.cfg"])print("[INFO] loading YOLO from disk...") net = cv2.dnn.readNetFromDarknet(configPath, weightsPath) ln = net.getLayerNames() ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]# 初始化VideoCapture類 vc = cv2.VideoCapture(args["input"]) writer = None (W, H) = (None, None)# 獲取視頻的總的幀數 try:prop = cv2.cv.CV_CAP_PROP_FRAME_COUNT if imutils.is_cv2() \else cv2.CAP_PROP_FRAME_COUNTtotal = int(vc.get(prop))print("[INFO] {} total frames in video".format(total))# an error occurred while trying to determine the total # number of frames in the video file except:print("[INFO] could not determine # of frames in video")print("[INFO] no approx. completion time can be provided")total = -1# 循環檢測視頻中的每一幀 while True:# 讀取幀# grabbed是一個bool,表示是否成功捕獲幀# frame是捕獲的幀(grabbed, frame) = vc.read()# 退出循環if not grabbed:break# 如果W,H為空,獲取第一幀的width、heightif W is None or H is None:(H, W) = frame.shape[:2]# 構造blob,并輸入到網絡中,執行Inferenceblob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416),swapRB=True, crop=False)net.setInput(blob)start = time.time()layerOutputs = net.forward(ln)end = time.time()# 初始化列表,保存bbx信息boxes = []confidences = []classIDs = []# 循環每一個輸出層的輸出for output in layerOutputs:# 循環該層輸出的每一個bbxfor detection in output:# 獲取當前bbx的信息scores = detection[5:]classID = np.argmax(scores)confidence = scores[classID]# 類別最大概率與設定的閾值相比較if confidence > args["confidence"]:# bbx的坐標信息box = detection[0:4] * np.array([W, H, W, H])(centerX, centerY, width, height) = box.astype("int")x = int(centerX - (width / 2))y = int(centerY - (height / 2))# 更新bbx列表boxes.append([x, y, int(width), int(height)])confidences.append(float(confidence))classIDs.append(classID)# 執行NMS算法,去除重復的bbxidxs = cv2.dnn.NMSBoxes(boxes, confidences, args["confidence"], args["threshold"])if len(idxs) > 0:# 循環提取每一個bbx坐標信息,使用OpenCV畫在圖上for i in idxs.flatten():# bbx坐標信息(x, y) = (boxes[i][0], boxes[i][1])(w, h) = (boxes[i][2], boxes[i][3])# 畫出bbxcolor = [int(c) for c in COLORS[classIDs[i]]]cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])cv2.putText(frame, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)# 檢查writer是否為空if writer is None:# 初始化VideoWriteerfourcc = cv2.VideoWriter_fourcc(*"MJPG")writer = cv2.VideoWriter(args["output"], fourcc, 30, (frame.shape[1], frame.shape[0]), True)# 輸出處理每一幀的時間,以及處理完視頻總的時間if total > 0:elap = (end - start)print("[INFO] single frame took {:.4f} seconds".format(elap))print("[INFO] estimated total time to finish: {:.4f}".format(elap * total))# 寫入當前幀writer.write(frame)# 釋放文件指針 print("[INFO] cleaning up...") writer.release() vc.release()轉載于:https://www.cnblogs.com/chenzhen0530/p/10758923.html
總結
以上是生活随笔為你收集整理的YOLO Object Detection with OpenCV的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tcp与ip协议的区别
- 下一篇: 设计模式之工厂模式(四)