yolov5 入学から習熟まで

目次

序章

ネットワーク構造

データ増強

配備

円と長方形を検出するためのデータを生成する

序章

2020 年 5 月 18 日のリリース以降、いくつかのバージョンが繰り返されており、最新バージョンは v7 であり、セグメンテーション機能が追加されています。YOLOv5ネットワークの詳しい解説 や、 YoloシリーズのYolov5のコアとなる基礎知識  など、yolov5の原理やマークされたデータの使い方を解説したブログ記事がたくさんあります。

インストールが簡単で使いやすいため、検出方法のデファクト ベンチマークとなっています。 

// 克隆代码库即可
git clone https://github.com/ultralytics/yolov5  # clone
cd yolov5
pip install -r requirements.txt  # install

を使用すると、1 行のコードで完了するだけです。

import torch
# 加载模型
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')  # or yolov5n - yolov5x6, custom
# 图片路径
img = 'https://ultralytics.com/images/zidane.jpg'  # or file, Path, PIL, OpenCV, numpy, list
# 执行检测推理
results = model(img)
# 检测结果可视化
results.print()  # or .show(), .save(), .crop(), .pandas(), etc.

何?コードを 1 行も書きたくない. コードなしで開発し、カメラから直接効果を確認したい場合は、ウェアハウスで detect.py を実行することも要件を満たすことができます。

python detect.py --weights yolov5s.pt --source 0

詳細なパラメーターの意味は次のとおりです。ここで、 --weights は使用するトレーニング前の重みを指定し、 --source は検出するソース (画像、画像パス リスト、カメラ、またはネットワーク プッシュ ストリーム) を指定します。 

python detect.py --weights yolov5s.pt --source 0                               # webcam
                                               img.jpg                         # image
                                               vid.mp4                         # video
                                               screen                          # screenshot
                                               path/                           # directory
                                               list.txt                        # list of images
                                               list.streams                    # list of streams
                                               'path/*.jpg'                    # glob
                                               'https://youtu.be/Zgi9g1ksQHc'  # YouTube
                                               'rtsp://example.com/media.mp4'  # RTSP, RTMP, HTTP stream
yolov5 v7.0 速度と精度の比較
coco の事前トレーニング済みモデルの mAP と速度

ネットワーク構造

YOLOv5 は、さまざまなサイズ ( n、  s、  m、  l、  ) に対してx全体的なネットワーク アーキテクチャは同じですが、各サブモジュールで異なる深さと幅を使用して、yamlファイル内のdepth_multipleパラメーターをそれぞれ処理しますwidth_multiplenまた、公式の,  smに加えてもあります. 違いは, 後者の方がより解像度の高い画像用であるということです. たとえばl, もちろん、 構造にはいくつかの違いがあります. 4前者は 32 回にダウンサンプリングし、3 つの予測フィーチャ レイヤーを使用するだけですが、予測フィーチャ レイヤー。xn6s6m6l6x61280x1280

以前のバージョンと比較すると、 YOLOv5 はv6.0バージョン後に小さな変更があり、ネットワークの最初の層 (元はモジュールFocus)が6x6大小の畳み込み層に置き換えられています。この 2 つは理論的には同等ですが、一部の既存の GPU デバイス (および対応する最適化アルゴリズム) では、モジュール6x6を使用するよりも大小の畳み込みレイヤーを使用する方が効率的です。Focus詳細については、この問題 #4825 を参照してください。下の図は元のFocusモジュール (前のものと同様Swin Transformer)Patch Mergingで、2x2隣接する各ピクセルを 1 つに分割しpatchpatchそれぞれの同じ位置 (同じ色) のピクセルをまとめて 4 にしfeature map、接続する3x3前のサイズの畳み込み層. 6x6これは、1 つのサイズの畳み込み層を直接使用することと同じです。

YOLOv5 6.0 の後、Focus を同等の 6x6 畳み込みレイヤーに置き換えて、展開を容易にします

ネック部分は(自社設計)SPPに交換し、両者の機能は同じですが、後者の方が効率的です。構造は、入力を複数の異なるサイズに並列に渡し、さらに融合を行うことで、ターゲットのマルチスケール問題をある程度解決できます。複数のサイズのレイヤーを介して入力をシリアル化する構造.ここで注意すべきは, 2 つのサイズのレイヤーをシリアル化した計算結果は 1 つのサイズのレイヤーの計算結果と同じであり, 3 つのサイズのレイヤーをシリアル化した計算結果は同一サイズのレイヤーと同じ レイヤーの計算結果は同じです。SPPFGlenn JocherSPPMaxPoolSPPF5x5MaxPool5x5MaxPool9x9MaxPool5x5MaxPool13x13MaxPool

SPPF ネットワーク構造図

データ増強

モザイク、4枚の写真を1枚の写真に結合

モザイク データの拡張

コピーペースト、いくつかのターゲットを画像にランダムに貼り付けます。データにはsegmentsデータ、つまり各ターゲットのインスタンスセグメンテーション情報が必要です。

コピー ペースト、スプリット トレーニングでのみ使用

Random affine(Rotation, Scale, Translation and Shear) はランダムにアフィン変換を行いますが、設定ファイルのハイパーパラメータによると、合計ScaleTranslation平行移動のみが使用されていることがわかります。

ランダム ラジアル変換の強化

MixUpは 2 つの画像を一定の透明度でブレンドすることです. それが有用かどうかは明らかではありません. 結局, 論文もアブレーション実験もありません. コードで使用されるのはより大きなモデルのみでMixUp、時間の 10% のみです。

混同する

Albumentations、主にフィルタリング、ヒストグラムの均等化、画質の変更などを行います。コードに記述されたコードは、パッケージがインストールされている場合にのみ有効になることがわかりますが、パッケージはプロジェクトファイルでコメントアウトされてalbumentationsいるrequirements.txtためalbumentations、デフォルトでは有効になっていません

Augment HSV(Hue, Saturation, Value) は、色相、彩度、明度をランダムに調整します。

ランダムな色の変化

ランダム横フリップ、ランダム横フリップ 

ランダムな水平反転。これはより一般的に使用されます

多くのトレーニング戦略が YOLOv5 ソース コードで使用されています

  • マルチスケールトレーニング(0.5~1.5x)、マルチスケールトレーニング、入力画像のサイズを640×640とすると、トレーニング時に使用するサイズは0.5×640~1.5×640の間でランダムに選択されるので注意どちらも 32 の整数倍です (ネットワークは最大 32 倍までダウンサンプリングするため)。
  • AutoAnchor (カスタム データのトレーニング用) では、独自のデータ セットをトレーニングするときに、再クラスター化して、独自のデータ セットの目標に従ってアンカー テンプレートを生成できます。
  • Warmup および Cosine LR スケジューラ、トレーニングの前にウォームアップしてWarmupから、Cosine学習率の低下戦略を使用します。
  • EMA (指数移動平均) は、トレーニング パラメーターに勢いを加えて更新プロセスをよりスムーズにするものと理解できます。
  • 混合精度、混合精度トレーニングは、GPU ハードウェア サポートが提供されている場合、ビデオ メモリの使用量を削減し、トレーニングを高速化できます。
  • ハイパーパラメータの進化、ハイパーパラメータの最適化、錬金術未経験者は触らないでデフォルトのままでいい。

YOLOv5 の損失は、主に次の 3 つの部分で構成されます。

  • クラス損失、分類損失が使用されますBCE loss。陽性サンプルの分類損失のみを計算することに注意してください。
  • Objectness loss , objthe loss, is still used BCE loss. これは、objネットワークと GT Box によって予測されたターゲット バウンディング ボックスを指すことに注意してくださいCIoUここで計算されるのは、objすべてのサンプルの損失です。
  • Location Loss、 Location Loss が使用されますCIoU loss。陽性サンプルの Location Loss のみを計算することに注意してください。

配備

yolov5 v6.0 (含まれていない) より前のバージョンでは、Focus レイヤーを使用するため、配置に多くの変更が加えられ、多くの複雑な操作が必要になります. 詳細については、詳細な記録を参照してください u バージョン YOLOv5 ターゲット検出 ncnn 実装 , 特定変更手順は次のとおり YOLOv5 を検出して ncnn モバイル端末に展開

// 1.导出onnx
python models/export.py --weights yolov5s.pt --img 320 --batch 1
// 2.简化模型
python -m onnxsim yolov5s.onnx yolov5s-sim.onnx
// 3. 模型转换到ncnn
./onnx2ncnn yolov5s-sim.onnx yolov5s.param yolov5s.bin
// 4. 编辑 yolov5s.param文件
第4行到13行删除(也就是Slice和Concat层),将第二行由172改成164(一共删除了10层,第二行的173更改为164,计算方法173-(10-1)=164)
增加自定义层
YoloV5Focus              focus                    1 1  images 159
其中159是刚才删除的Concat层的输出
// 5. 支持动态尺寸输入
将reshape中的960,240,60更改为-1,或者其他 0=后面的数
// 6. ncnnoptimize优化
./ncnnoptimize yolov5s.param yolov5s.bin yolov5s-opt.param yolov5s-opt.bin 1

v6.0 以降では、代わりに 6x6 畳み込みを使用する方がはるかに便利です. デプロイに opencv の dnn モジュールを直接使用できます. 詳細については、YOLOv5、O​​penCV、Python、および C++ を使用したオブジェクトの検出を参照してください。コード yolov5-opencv - cpp -python

ただし、opencv4.5.5以降としか連携できないので注意が必要で、主に6つのステップが含まれています。

// 1.加载模型
net = cv2.dnn.readNet('yolov5s.onnx')
// 2.加载图片
def format_yolov5(source):

    # put the image in square big enough
    col, row, _ = source.shape
    _max = max(col, row)
    resized = np.zeros((_max, _max, 3), np.uint8)
    resized[0:col, 0:row] = source
    
    # resize to 640x640, normalize to [0,1[ and swap Red and Blue channels
    result = cv2.dnn.blobFromImage(resized, 1/255.0, (640, 640), swapRB=True)
    
    return result
// 3.执行推理
predictions = net.forward()
output = predictions[0]
// 4.展开结果
def unwrap_detection(input_image, output_data):
    class_ids = []
    confidences = []
    boxes = []

    rows = output_data.shape[0]

    image_width, image_height, _ = input_image.shape

    x_factor = image_width / 640
    y_factor =  image_height / 640

    for r in range(rows):
        row = output_data[r]
        confidence = row[4]
        if confidence >= 0.4:

            classes_scores = row[5:]
            _, _, _, max_indx = cv2.minMaxLoc(classes_scores)
            class_id = max_indx[1]
            if (classes_scores[class_id] > .25):

                confidences.append(confidence)

                class_ids.append(class_id)

                x, y, w, h = row[0].item(), row[1].item(), row[2].item(), row[3].item() 
                left = int((x - 0.5 * w) * x_factor)
                top = int((y - 0.5 * h) * y_factor)
                width = int(w * x_factor)
                height = int(h * y_factor)
                box = np.array([left, top, width, height])
                boxes.append(box)

// 5.非极大值抑制
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.25, 0.45) 

result_class_ids = []
result_confidences = []
result_boxes = []

for i in indexes:
    result_confidences.append(confidences[i])
    result_class_ids.append(class_ids[i])
    result_boxes.append(boxes[I])
// 6.可视化结果输出

class_list = []
with open("classes.txt", "r") as f:
    class_list = [cname.strip() for cname in f.readlines()]

colors = [(255, 255, 0), (0, 255, 0), (0, 255, 255), (255, 0, 0)]

for i in range(len(result_class_ids)):

    box = result_boxes[i]
    class_id = result_class_ids[i]

    color = colors[class_id % len(colors)]

    conf  = result_confidences[i]

    cv2.rectangle(image, box, color, 2)
    cv2.rectangle(image, (box[0], box[1] - 20), (box[0] + box[2], box[1]), color, -1)
    cv2.putText(image, class_list[class_id], (box[0] + 5, box[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0))

円と長方形を検出するためのデータを生成する

次に、円と長方形を検出するプロジェクトは、yolov5 のトレーニング データの生成とトレーニング プロセスを示しています。しかし、データのラベル付けには時間と労力がかかります.生成されたデータを使用して、いくつかの実験を迅速に検証できれば素晴らしいと思いませんか.

Lable Studio [yoloV5 実戦記録] に基づく Xiaobai は、独自のデータセットをトレーニングすることもできます! labelimg に基づいて、深層学習を使用してオブジェクト検出を行う方法を教えます (2): データのラベル付け - プログラマー

yolov5 のラベリング フォーマットは非常にシンプルです. 写真は images フォルダに配置されます. labels フォルダの下に, 各写真ファイルには対応する同名の txt ファイルがあり, 各ターゲットのカテゴリ, 正規化された座標と幅が行ごとに保存されます.高く、多くの注釈ツールが yolo 注釈形式の直接エクスポートをサポートしており、VOC、coco などの形式から YOLO 形式に簡単に変換できるスクリプトも多数あります。

类别1 归一化中心点坐标x 归一化中心坐标y 归一化宽度 归一化高度
类别2 归一化中心点坐标x 归一化中心坐标y 归一化宽度 归一化高度
注釈ファイルの例

1. ここでは、検出円を例に、各ステップを詳しく紹介します。

1つ目は学習データの生成と可視化で、ランダムな点を中心に検出したい対象を半径60~100の円でランダムに描き、合計10万個の学習データを生成する

import os
import cv2
import math
import random
import numpy as np
from tqdm import tqdm

def generate():
    img = np.zeros((640,640,3),np.uint8)
    x = 100+random.randint(0, 400)
    y = 100+random.randint(0, 400)
    radius = random.randint(60,100)
    r = random.randint(0,255)
    g = random.randint(0,255)
    b = random.randint(0,255)
    cv2.circle(img, (x,y), radius, (b,g,r),-1)
    return img, [x,y,radius]

def generate_batch(num=10000):
    images_dir = "data/circle/images"
    if not os.path.exists(images_dir):
        os.makedirs(images_dir)
    labels_dir = "data/circle/labels"
    if not os.path.exists(labels_dir):
            os.makedirs(labels_dir)
    for i in tqdm(range(num)):
        img, labels = generate()
        cv2.imwrite(images_dir+"/"+str(i)+".jpg", img)
        with open(labels_dir+"/"+str(i)+".txt", 'w') as f:
            x, y, radius = labels
            f.write("0 "+str(x/640)+" "+str(y/640)+" "+str(2*radius/640)+" "+str(2*radius/640)+"\n")

def show_gt(dir='data/circle'):
    files = os.listdir(dir+"/images")
    gtdir = dir+"/gt"
    if not os.path.exists(gtdir):
        os.makedirs(gtdir)
    for file in tqdm(files):
        imgpath = dir+"/images/"+file
        img = cv2.imread(imgpath)
        h,w,_ = img.shape
        labelpath = dir+"/labels/"+file[:-3]+"txt"
        with open(labelpath) as f:
            lines = f.readlines()
            for line in lines:
                items = line[:-1].split(" ")
                c = int(items[0])
                cx = float(items[1])
                cy = float(items[2])
                cw = float(items[3])
                ch = float(items[4])
                x1 = int((cx - cw/2)*w)
                y1 = int((cy - ch/2)*h)
                x2 = int((cx + cw/2)*w)
                y2 = int((cy + ch/2)*h)
                cv2.rectangle(img, (x1,y1),(x2,y2),(0,255,0),2)
            cv2.imwrite(gtdir+"/"+file, img)

if __name__=="__main__":
    generate_batch()
    show_gt()

次に、circle.yaml を作成します

train: data/circle/images/
val: data/circle/images/
# number of classes
nc: 1

# class names
names: ['circle']

2. 円形および長方形のターゲットを検出する場合は、生成スクリプトとデータ構成ファイルを調整する必要があります

import os
import cv2
import math
import random
import numpy as np
from tqdm import tqdm

def generate_circle():
    img = np.zeros((640,640,3),np.uint8)
    x = 100+random.randint(0, 400)
    y = 100+random.randint(0, 400)
    radius = random.randint(60,100)
    r = random.randint(0,255)
    g = random.randint(0,255)
    b = random.randint(0,255)
    cv2.circle(img, (x,y), radius, (b,g,r),-1)
    return img, [x,y,radius*2,radius*2]

def generate_rectangle():
    img = np.zeros((640,640,3),np.uint8)
    x1 = 100+random.randint(0, 400)
    y1 = 100+random.randint(0, 400)
    w = random.randint(80, 200)
    h = random.randint(80, 200)
    x2 = x1 + w
    y2 = y1 + h
    r = random.randint(0,255)
    g = random.randint(0,255)
    b = random.randint(0,255)
    cx = (x1+x2)//2
    cy = (y1+y2)//2
    cv2.rectangle(img, (x1,y1), (x2,y2), (b,g,r),-1)
    return img, [cx,cy,w,h]

def generate_batch(num=100000):
    images_dir = "data/shape/images"
    if not os.path.exists(images_dir):
        os.makedirs(images_dir)
    labels_dir = "data/shape/labels"
    if not os.path.exists(labels_dir):
            os.makedirs(labels_dir)
    for i in tqdm(range(num)):
        if i % 2 == 0:
            img, labels = generate_circle()
        else:
            img, labels = generate_rectangle()
        cv2.imwrite(images_dir+"/"+str(i)+".jpg", img)
        with open("data/shape/labels/"+str(i)+".txt", 'w') as f:
            cx,cy,w,h = labels
            f.write(str(i%2)+" "+str(cx/640)+" "+str(cy/640)+" "+str(w/640)+" "+str(h/640)+"\n")

def show_gt(dir='data/shape'):
    files = os.listdir(dir+"/images")
    gtdir = dir+"/gt"
    if not os.path.exists(gtdir):
        os.makedirs(gtdir)
    for file in tqdm(files):
        imgpath = dir+"/images/"+file
        img = cv2.imread(imgpath)
        h, w, _ = img.shape
        labelpath = dir+"/labels/"+file[:-3]+"txt"
        with open(labelpath) as f:
            lines = f.readlines()
            for line in lines:
                items = line[:-1].split(" ")
                c = int(items[0])
                cx = float(items[1])
                cy = float(items[2])
                cw = float(items[3])
                ch = float(items[4])
                x1 = int((cx - cw/2)*w)
                y1 = int((cy - ch/2)*h)
                x2 = int((cx + cw/2)*w)
                y2 = int((cy + ch/2)*h)
                cv2.rectangle(img, (x1,y1),(x2,y2),(0,255,0),2)
                cv2.putText(img, str(c), (x1,y1), 3,1,(0,0,255))
            cv2.imwrite(gtdir+"/"+file, img)

if __name__=="__main__":
    generate_batch()
    show_gt()

 対応する shape.yaml は、カテゴリ数が 2 であることに注意してください

train: data/shape/images/
val: data/shape/images/
# number of classes
nc: 2

# class names
names: ['circle', 'rectangle']

訓練

次のコマンドでトレーニングを開始します

python train.py --data circle.yaml --cfg yolov5s.yaml --weights '' --batch-size 64

円形と長方形の 2 種類のターゲットがある場合、コマンドは

python train.py --data shape.yaml --cfg yolov5s.yaml --weights '' --batch-size 64

​​​​​​​  

トレーニング中に出力された統計、カテゴリ、および分布を見てください。

 

いくつかのエポックをトレーニングして結果を確認する

               epoch,      train/box_loss,      train/obj_loss,      train/cls_loss,   metrics/precision,      metrics/recall,     metrics/mAP_0.5,metrics/mAP_0.5:0.95,        val/box_loss,        val/obj_loss,        val/cls_loss,               x/lr0,               x/lr1,               x/lr2
                   0,             0.03892,            0.011817,                   0,             0.99998,             0.99978,               0.995,             0.92987,           0.0077891,           0.0030948,                   0,           0.0033312,           0.0033312,            0.070019
                   1,            0.017302,           0.0049876,                   0,                   1,              0.9999,               0.995,             0.99105,           0.0031843,           0.0015662,                   0,           0.0066644,           0.0066644,            0.040019
                   2,            0.011272,           0.0034826,                   0,                   1,             0.99994,               0.995,             0.99499,           0.0020194,           0.0010969,                   0,           0.0099969,           0.0099969,            0.010018
                   3,           0.0080153,           0.0027186,                   0,                   1,             0.99994,               0.995,               0.995,           0.0013095,          0.00083033,                   0,           0.0099978,           0.0099978,           0.0099978
                   4,           0.0067639,           0.0023831,                   0,                   1,             0.99996,               0.995,               0.995,          0.00099513,          0.00068878,                   0,           0.0099978,           0.0099978,           0.0099978
                   5,           0.0061637,           0.0022279,                   0,                   1,             0.99996,               0.995,               0.995,          0.00090497,          0.00064193,                   0,           0.0099961,           0.0099961,           0.0099961
                   6,           0.0058844,            0.002144,                   0,             0.99999,             0.99998,               0.995,               0.995,           0.0009117,          0.00063328,                   0,           0.0099938,           0.0099938,           0.0099938
                   7,           0.0056247,             0.00208,                   0,             0.99999,             0.99999,               0.995,               0.995,          0.00086355,          0.00061343,                   0,           0.0099911,           0.0099911,           0.0099911
                   8,           0.0054567,           0.0020223,                   0,                   1,             0.99999,               0.995,               0.995,          0.00081632,          0.00059592,                   0,           0.0099879,           0.0099879,           0.0099879
                   9,           0.0053597,           0.0019864,                   0,                   1,                   1,               0.995,               0.995,          0.00081379,          0.00058942,                   0,           0.0099842,           0.0099842,           0.0099842
                  10,           0.0053103,           0.0019559,                   0,                   1,                   1,               0.995,               0.995,           0.0008175,          0.00058669,                   0,             0.00998,             0.00998,             0.00998
                  11,           0.0052146,           0.0019445,                   0,                   1,                   1,               0.995,               0.995,          0.00083248,          0.00058731,                   0,           0.0099753,           0.0099753,           0.0099753
                  12,           0.0050852,           0.0019065,                   0,                   1,                   1,               0.995,               0.995,          0.00085092,          0.00058853,                   0,           0.0099702,           0.0099702,           0.0099702
                  13,           0.0050589,           0.0019031,                   0,                   1,                   1,               0.995,               0.995,          0.00086915,          0.00059267,                   0,           0.0099645,           0.0099645,           0.0099645
                  14,           0.0049664,           0.0018693,                   0,                   1,                   1,               0.995,               0.995,          0.00090856,          0.00059815,                   0,           0.0099584,           0.0099584,           0.0099584
                  15,           0.0049839,           0.0018568,                   0,                   1,                   1,               0.995,               0.995,          0.00093147,          0.00060425,                   0,           0.0099517,           0.0099517,           0.0099517
                  16,           0.0049079,           0.0018459,                   0,                   1,                   1,               0.995,               0.995,           0.0009656,          0.00061124,                   0,           0.0099446,           0.0099446,           0.0099446
                  17,           0.0048693,           0.0018277,                   0,                   1,                   1,               0.995,               0.995,          0.00099703,          0.00061948,                   0,            0.009937,            0.009937,            0.009937
                  18,           0.0048052,           0.0018103,                   0,                   1,                   1,               0.995,               0.995,           0.0010246,          0.00062618,                   0,           0.0099289,           0.0099289,           0.0099289
                  19,           0.0047608,           0.0017947,                   0,                   1,                   1,               0.995,               0.995,           0.0010439,          0.00063123,                   0,           0.0099203,           0.0099203,           0.0099203

mAP は 99.5+ に達しました。これは非常に優れています。予測結果を見てください。

  

PR曲線

円形および長方形のオブジェクト

  

配備

最後に、次のコマンドを使用して検出します。パスをローカル パスに置き換えることを忘れないでください。

python detect.py --weights exps/yolov5s_circle/weights/best.pt --source data/circle/images

 

組み込みのデモは長すぎるため、さまざまな形式と互換性がありません。また、onnx の展開コードははるかに単純です。

import cv2
import numpy as np
import torch
from torchvision import transforms
import onnxruntime
from utils.general import non_max_suppression

def detect(img, ort_session):
    img = img.astype(np.float32)
    img = img / 255
    img_tensor = img.transpose(2,0,1)[None]
    ort_inputs = {ort_session.get_inputs()[0].name: img_tensor}
    pred = torch.tensor(ort_session.run(None, ort_inputs)[0])
    dets = non_max_suppression(pred, 0.25, 0.45)
    return dets[0]

def demo():
    ort_session = onnxruntime.InferenceSession("yolov5s.onnx",  providers=['TensorrtExecutionProvider'])
    img = cv2.imread("data/images/bus.jpg")
    img = cv2.resize(img,(640,640))
    dets = detect(img, ort_session)
    for det in dets:
        x1 = int(det[0])
        y1 = int(det[1])
        x2 = int(det[2])
        y2 = int(det[3])
        score = float(det[4])
        cls = int(det[5])
        info = "{}_{:.2f}".format(cls, score*100)
        cv2.rectangle(img, (x1,y1),(x2,y2),(255,255,0))
        cv2.putText(img, info, (x1,y1), 1, 1, (0,0,255))
    cv2.imwrite("runs/detect/bus.jpg", img)
if __name__=="__main__":
    demo()

要約する

この記事では、円検出と四角形検出の 2 つの例を通じてトレーニング データに必要なラベルを生成する方法を詳細に説明し、トレーニング、テスト、展開のプロセス全体のコード実装を提供します。

おすすめ

転載: blog.csdn.net/minstyrain/article/details/123486914