Yolo3、Tiny-Yolo3での独自学習モデルをPythonに実装
画像検出に向けて、AlexeyAB Darknetを用いて、YOLO3、Tiny-YOLO3で作成した、独自学習モデルをPythonで実装します。
前提条件
YOLO2 Tiny-YOLO2 YOLO3 Tiny-YOLO3 をPythonで実装
学習済みモデル(weightsファイル)とコンフィグファイル(cfgファイル)
「darknet\build\darknet\x64\cfg\obj.data」ファイルのbackupに指定したフォルダに、学習モデル(weightsファイル)が出力されます。
classes = 7 train = train.txt valid = test.txt names = cfg/obj.names backup = backup/
独自学習に用いたコンフィグファイルは、「darknet\build\darknet\x64\cfg\」フォルダ内で作成していると思いますので、独自学習時に用いたcfgファイルとなります。
これらのファイルを、画像検出を実施するRaspberry PiやサーバーのPythonファイルが読み込み可能な場所にコピーします。
Python3での実装
- net = cv.dnn.readNetFromDarknet(CFG, MODEL)
- CFG:学習モデル(weightsファイル)
- MODEL:独自学習時に用いたcfgファイル
- net.setPreferableTarget
- net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
Raspberry PiやWindowsなどで動作させる際のTarget指定。
現時点では、OpenCVのYOLO向けDNNでは、GPUはサポートされておりません。 - net.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)
Intel Movidius Neural Compute Stick 2 (NCS2)を利用する際は、TargetにNCS2を指定することが出来ます。Raspberry Pi 3B +で動作確認済みとなります。
- net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
参考記事:Movidius Neural Compute Stick 2、OpenVINO™ toolkit for Raspbian* OS導入
Python3 ソースコード
サンプルスクリプトを掲載しておきます。
#!/usr/bin/env python # coding: utf-8 target_model = "yolov3-tiny-janken_final.weights" target_config = "yolov3-tiny-janken.cfg" import cv2 as cv import numpy as np MODEL = "./janken_cfg/" + target_model CFG = "./janken_cfg/" + target_config SCALE = 0.00392 ##1/255 INP_SHAPE = (416, 416) #input size MEAN = 0 RGB = True # Load a network net = cv.dnn.readNetFromDarknet(CFG, MODEL) net.setPreferableBackend(cv.dnn.DNN_BACKEND_DEFAULT) ##net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU) net.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD) confThreshold = 0.8 # Confidence threshold nmsThreshold = 0.8 # Non-maximum supression threshold class_names = ['active', 'goo', 'choki', 'pa', 'won', 'lose', 'draw'] def getOutputsNames(net): layersNames = net.getLayerNames() return [layersNames[i[0] - 1] for i in net.getUnconnectedOutLayers()] def postprocess(frame, outs): frameHeight = frame.shape[0] frameWidth = frame.shape[1] def drawPred(classId, conf, left, top, right, bottom): left = int(left) top = int(top) right = int(right) bottom = int(bottom) # Draw a bounding box. cv.rectangle(frame, (left, top), (right, bottom), (0, 255, 0)) label = class_names[classId] + '_%.2f' % conf labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1) top = max(top, labelSize[1]) cv.rectangle(frame, (left, top - labelSize[1]), (left + labelSize[0], top + baseLine), (255, 255, 255), cv.FILLED) cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0)) layerNames = net.getLayerNames() lastLayerId = net.getLayerId(layerNames[-1]) lastLayer = net.getLayer(lastLayerId) classIds = [] confidences = [] boxes = [] if lastLayer.type == 'Region': classIds = [] confidences = [] boxes = [] for out in outs: for detection in out: scores = detection[5:] classId = np.argmax(scores) confidence = scores[classId] 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 = center_x - width / 2 top = center_y - height / 2 classIds.append(classId) confidences.append(float(confidence)) boxes.append([left, top, width, height]) else: print('Unknown output layer type: ' + lastLayer.type) exit() indices = cv.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] drawPred(classIds[i], confidences[i], left, top, left + width, top + height) c = cv.VideoCapture(0) c.set(cv.CAP_PROP_FRAME_WIDTH, 640) # カメラ画像の横幅を1280に設定 c.set(cv.CAP_PROP_FRAME_HEIGHT, 480) # カメラ画像の縦幅を720に設定 c.read() r, frame = c.read() frameHeight = frame.shape[0] frameWidth = frame.shape[1] # Create a 4D blob from a frame. inpWidth = INP_SHAPE[0] inpHeight = INP_SHAPE[1] blob = cv.dnn.blobFromImage(frame, SCALE, (inpWidth, inpHeight), MEAN, RGB, crop=False) # Run a model net.setInput(blob) outs = net.forward(getOutputsNames(net)) ##print(outs) postprocess(frame, outs) # Put efficiency information. t, _ = net.getPerfProfile() label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency()) cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0)) #対象ファイルコピー保存 target_filepath = './result.jpg' cv.imwrite(target_filepath, frame)