深層学習による移動物体検知(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()
出力結果: