OpenCVの例 (9) ディープラーニングによる移動物体検出 (3) YOLOv3 物体認識


物体検出とは、大まかに言うと、画像や動画を入力し、処理後に物体の位置情報(左上隅や右下隅の座標など)や、物体の予測カテゴリ、ターゲットの予測信頼度。先ほど多くの理論的知識を説明しましたが、今度はそれを実際に行う必要があります。初心者にとって、YOLO アルゴリズムを自分で実装するのは現実的ではありませんが、幸いなことに、OpenCV の DNN (ディープ ニューラル ネットワーク) モジュールは Darknet フレームワークをカプセル化しています (YOLO アルゴリズムをカプセル化しています)。OpenCV を使用してトレーニング済みの深層学習モデルを直接実行する方が便利です。今回は、ターゲット検出に最も強力な YOLOv3 を使用します。基本的な手順は、OpenCV に事前トレーニング済みの YOLOv3 モデルをロードさせ、その後画像認識などのさまざまな検出を実行し、コンピューターには物体検出などのための独自のカメラが搭載されています。

事前トレーニングされた YOLOv3 モデルをロードするには、yolov3.cfg、yolov3.weights、および coco.names の 3 つのファイル (プロジェクト ディレクトリ内) を準備する必要があります。このうち、yolov3.cfg は yolov3 ネットワーク構成ファイル、yolov3.weights は重みファイル、coco.names はラベル ファイルです。

1. YOLOv3に基づいてオブジェクトを認識する

OpenCV dnn モジュールを使用して YOLO モデルをロードします。コードは次のとおりです。

     net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")

coco.names からカテゴリをインポートし、リストとして保存します。コードは次のとおりです。

classes = []
with open("coco.names","r")as f:
	classes = [line.strip() for line inf.readlines()]
print(classes)

完全なコード:

import cv2
import numpy as np

net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
classes = []
with open("coco.names", "r") as f:   #这里使用的是coco所训练的模型yolov3.cfg所以这里对应为coco.names
    classes = [line.strip() for line in f.readlines()]

print(classes)

layer_names = net.getLayerNames()
print(layer_names)
      
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
print(output_layers)

img = cv2.imread("demo1.jpg")

# 获取图像尺寸与通道值
height, width, channels = img.shape
print('The image height is:',height)
print('The image width is:',width)
print('The image channels is:',channels)

blob = cv2.dnn.blobFromImage(img, 1.0 / 255.0, (416, 416), (0, 0, 0), True, crop=False)


from matplotlib import pyplot as plt
 
fig = plt.gcf()
fig.set_size_inches(20, 10)

num = 0
for b in blob:
    for img_blob in b:
        img_blob=cv2.cvtColor(img_blob, cv2.COLOR_BGR2RGB)
        num += 1
        ax = plt.subplot(3/3, 3, num)
        ax.imshow(img_blob)
        title = 'blob_image:{}'.format(num)
        ax.set_title(title, fontsize=20)


net.setInput(blob)
outs = net.forward(output_layers)

for i in range(len(outs)):
    print('The {} layer out shape is:'.format(i), outs[i].shape)

class_ids = []
confidences = []
boxes = []

i = 0
for out in outs:
    for detection in out:
        a = sum(detection[5:])
        if a > 0:
            print(detection[5:])
            i += 1
        if i == 2:
            break
 

i = 0
for out in outs:
    for detection in out:
        print('中心像素坐标 X 对原图宽比值:',detection[0])
        print('中心像素坐标 Y 对原图高比值:',detection[1])
        print('边界框的宽度 W 对原图宽比值:',detection[2])
        print('边界框的高度 H 对原图高比值:',detection[3])
        print('此边界框置信度:',detection[4])
        break
    break
 



plt_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

fig = plt.gcf()
fig.set_size_inches(20, 10)

plt.imshow(plt_img)

# jupyter 对每次运行结果会保留,再次运行列表创建
class_ids = []
confidences = []
boxes = []

i = 0

for out in outs:
    for detection in out:
        scores = detection[5:]
        class_id = np.argmax(scores)
        confidence = scores[class_id]
        if confidence > 0.5:
            center_x = int(detection[0] * width)
            center_y = int(detection[1] * height)
            
            w = int(detection[2] * width)        
            h = int(detection[3] * height)
            x = int(center_x - w / 2)
            y = int(center_y - h / 2)

            boxes.append([x, y, w, h])
            confidences.append(float(confidence))
            class_ids.append(class_id)
            label = classes[class_id]
            plt.gca().add_patch(
            plt.Rectangle((x, y), w,
                          h, fill=False,
                          edgecolor=(0, 1, 1), linewidth=2)
            )
            plt.text(x, y - 10, label, color = (1, 0, 0), fontsize=20)
            
            print('object {} :'.format(i), label)
            i += 1

plt.show()
  

plt_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

fig = plt.gcf()
fig.set_size_inches(30, 20)

ax_img = plt.subplot(1, 2, 1)

ax_img.imshow(plt_img)

# jupyter 对每次运行结果会保留,再次运行一次
class_ids = []
confidences = []
boxes = []

i = 0

for out in outs:
    for detection in out:
        scores = detection[5:]
        class_id = np.argmax(scores)
        confidence = scores[class_id]
        if confidence > 0.5:
            center_x = int(detection[0] * width)
            center_y = int(detection[1] * height)
            
            w = int(detection[2] * width)        
            h = int(detection[3] * height)
            x = int(center_x - w / 2)
            y = int(center_y - h / 2)

            boxes.append([x, y, w, h])
            confidences.append(float(confidence))
            class_ids.append(class_id)
            label = classes[class_id]
            plt.gca().add_patch(
            plt.Rectangle((x, y), w,
                          h, fill=False,
                          edgecolor=(0, 1, 1), linewidth=2)
            )
            plt.text(x, y - 10, label, color = (1, 0, 0), fontsize=20)
            
            print('object {} :'.format(i), label + ' '*(10 - len(label)), 'confidence :{}'.format(confidence))
            i += 1

print(confidences)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
print(indexes, end='')

ax_img = plt.subplot(1, 2, 2)
ax_img.imshow(plt_img)
for j in range(len(boxes)):
    if j in indexes:
        x, y, w, h = boxes[j]
        label = classes[class_ids[j]]
        plt.gca().add_patch(
            plt.Rectangle((x, y), w,
                          h, fill=False,
                          edgecolor=(0, 1, 1), linewidth=2)
            )
        plt.text(x, y - 10, label, color = (1, 0, 0), fontsize=20)
        

plt.show()
 

出力層を取得するコードは次のとおりです。

     layer_names = net.getLayerNames()
     print(layer_names)
     
     output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
     print(output_layers)

このうち、getLayerNames 関数はネットワークの各層の名前を取得し、getUnconnectedOutLayers 関数は未接続の出力を持つ層インデックスを返します。

画像を処理して BLOB を取得するコードを追加します。

    img = cv2.imread("demo1.jpg")
    # 获取图像尺寸与通道值
    height, width, channels = img.shape
    print('The image height is:',height)
    print('The image width is:',width)
    print('The image channels is:',channels)
    
    blob = cv2.dnn.blobFromImage(img, 1.0 / 255.0, (416, 416), (0, 0, 0), True,
crop=False)

この時点でプログラムを実行すると、印刷される高さ、幅、チャネル数は次のようになります。

     The image height is: 2250
     The image width is: 4000
     The image channels is: 3

(Matplotlib 視覚化 BLOB の下に画像を追加します。コードは次のとおりです。

     from matplotlib import pyplot as plt

OpenCV は BGR を使用し、Matplotlib は RGB を使用します。BGR を RGB に変換するには cv2.COLOR_BGR2RGB を使用する必要があります。

setInput 関数を使用して BLOB をネットワークに入力し、forward 関数を使用してネットワーク出力層の名前を入力し、ネットワーク出力を計算します。この計算では、output_layers には 3 つの出力レイヤーのリストが含まれるため、outs の値も 3 つの行列 (配列) を含むリスト (リスト) になります。
このループは次を出力します。

     The 0 layer out shape is: (507, 85)
     The 1 layer out shape is: (2028, 85)
     The 2 layer out shape is: (8112, 85)

その後、識別とラベル付けが行われ、記録されたデータのリストが作成されます。
このうち、class_ids はカテゴリ名を記録し、confidences はアルゴリズムによってオブジェクトが検出される確率を記録し、box はボックスの座標を記録します。416×416 の入力画像の場合、YOLOv3 は各スケールの特徴マップの各グリッドに 3 つの事前ボックスを設定し、合計 13×13×3 + 26×26×3 + 52×52×3 = 10647 の予測が存在します。 。各予測は 85 (4+1+80) 次元ベクトルであり、フレーム座標 (4 つの値)、フレーム信頼度 (1 つの値)、オブジェクト カテゴリの確率 (COCO データセットの場合、80 のオブジェクトがあります) が含まれるため、次のようになります。 detect[5:] を通じて検出の最後の 80 データ (ワンホット コードと同様) を取得し、その最大インデックスに対応する coco.names カテゴリを取得します。

ここに画像の説明を挿入
検出中に、ダブル フレーム (またはマルチ フレーム) 効果が現れることが判明しました。OpenCV dnn モジュールには NMSBoxes() 関数が付属しており、NMS アルゴリズムを使用してマルチボックスの問題を解決できます。NMS の目的は、近傍内の同じ検出ターゲットの信頼度が最も高いボックスを保持することです。以下の出力では、最も高い信頼値を持つボックス インデックスのみが同じターゲットの検出用に予約されていることがわかります。オブジェクト 0: tvmonitor やオブジェクト 3: tvmonitor などの近傍にある確率は、それぞれ 0.9334805607795715 と 0.9716598987579346 です。明らかに、オブジェクト 3: tvmonitor は予約されており、インデックスには [0] 要素はありません。残りの推論似ています。

ここに画像の説明を挿入

2. オブジェクトの種類ごとにキャプチャフレームの色を変える

コード:

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Load Yolo
net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
classes = []
with open("coco.names", "r") as f:
    classes = [line.strip() for line in f.readlines()]

layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]

colors = np.random.uniform(0, 255, size=(len(classes), 3)) / 255

# Loading image
img = cv2.imread("demo1.jpg")
# img = cv2.resize(img, None, fx=0.4, fy=0.4)
height, width, channels = img.shape

# Detecting objects
blob = cv2.dnn.blobFromImage(img, 1.0 / 255.0, (416, 416), (0, 0, 0), True, crop=False)

net.setInput(blob)
outs = net.forward(output_layers)

# Showing informations on the screen
class_ids = []
confidences = []
boxes = []

fig = plt.gcf()
fig.set_size_inches(20, 10)
plt_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(plt_img)

for out in outs:
    for detection in out:
        scores = detection[5:]
        class_id = np.argmax(scores)
        confidence = scores[class_id]
        if confidence > 0.5:
            # Object detected
            center_x = int(detection[0] * width)
            center_y = int(detection[1] * height)
            w = int(detection[2] * width)
            h = int(detection[3] * height)

            # Rectangle coordinates
            x = int(center_x - w / 2)
            y = int(center_y - h / 2)

            boxes.append([x, y, w, h])
            confidences.append(float(confidence))
            class_ids.append(class_id)

indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

for i in range(len(boxes)):
    if i in indexes:
        x, y, w, h = boxes[i]
        label = str(classes[class_ids[i]])
        color = colors[i]
        plt.gca().add_patch(
            plt.Rectangle((x, y), w,
                          h, fill=False,
                          edgecolor=color, linewidth=2)
            )
        plt.text(x, y - 10, label, color = color, fontsize=20)
 

plt.show()
 

 

操作結果:

ここに画像の説明を挿入

3. Matplotlibを使わずにターゲット検出を実現

コード:

import cv2
import numpy as np

# Load Yolo
net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
classes = []
with open("coco.names", "r") as f:
    classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
colors = np.random.uniform(0, 255, size=(len(classes), 3))

# Loading image
img = cv2.imread("demo1.jpg")
height, width, channels = img.shape

# Detecting objects
blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
        
net.setInput(blob)
outs = net.forward(output_layers)

# Showing informations on the screen
class_ids = []
confidences = []
boxes = []
for out in outs:
    for detection in out:
        scores = detection[5:]
        class_id = np.argmax(scores)
        confidence = scores[class_id]
        if confidence > 0.5:
            # Object detected
            center_x = int(detection[0] * width)
            center_y = int(detection[1] * height)
            w = int(detection[2] * width)
            h = int(detection[3] * height)

            # Rectangle coordinates
            x = int(center_x - w / 2)
            y = int(center_y - h / 2)

            boxes.append([x, y, w, h])
            confidences.append(float(confidence))
            class_ids.append(class_id)

indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

font = cv2.FONT_HERSHEY_SIMPLEX
for i in range(len(boxes)):
    if i in indexes:
        x, y, w, h = boxes[i]
        label = str(classes[class_ids[i]])
        color = colors[i]
        cv2.rectangle(img, (x, y), (x + w, y + h), color, 3)
        cv2.putText(img, label, (x, y - 20), font, 2, color, 3)

cv2.namedWindow("Image",0)
cv2.resizeWindow("Image", 1600, 900)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

出力結果:

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_41600018/article/details/132395409