【ターゲット検出シリーズ】yolov3、yolov4が独自のデータをトレーニング(pytorchバージョン)

 

主な内容:理論の一部。独自のデータセットを準備し、予測をトレーニングする方法。Windowsの下でvs2017のトレーニング済みモデルメソッドを呼び出します。

PS:yolov3とyolov4は統合されていますが、違いは、それらがcfgファイルを変更し、事前にトレーニングされたネットワークをロードすることです。トレーニングプロセスでは、v4 GPUが変動しており、v3はある値で安定しており、v4はv3のバッチサイズ設定よりもはるかに小さく、トレーニングは遅いことがわかりました。

1.コードアドレス

https://github.com/ultralytics/yolov3

2.原則:主にネットワーク構造につ​​いて話します。これを見ないと、コードに対応しないからです。ネットワーク出力はまだ画像です。赤い部分はdarknet53などのネットワークのバックボーンと見なすことができ青い部分は13 * 13層出力結果、オレンジの部分は26 * 26層の出力結果緑の部分は52 * 52レイヤー。出力結果。この13 * 13の起源。元の画像416 * 416は32倍にズームされました。それだけです。この図は、cfgファイルの多くのパラメーターに1対1で対応しています。対応する関係については、https://blog.csdn.net/gbz3300255/article/details/106255335を参照してくださいコードに対応する必要があるため、主に入力と出力に焦点を当てます

3つのカラーサークルがある理由は、マルチスケール検出のためです。3回の検出では、対応する受容野が毎回異なります.32回のダウンサンプリングの受容野が最大で、大きなターゲットの検出に適しており16回は一般的なサイズのオブジェクトに適しており、8回の受容野は最小で、小さなターゲットの検出に適しています。特定のアンカーボックスのサイズは、cfgファイルで設定されます。下の図に示すように、赤い色はアンカーの中心を示します。

損失関数の計算方法、およびアプリオリボックスの作成方法については説明しません。ここでは入力と出力のみ。

上記のコードの入力と出力は次のとおりです

入力:それが416 * 416 * 3の画像であると仮定します。(デフォルトの入力サイズプログラムは320 * 640です。独自のデータをトレーニングするときは注意してください)

出力: [1、(13 * 13 + 26 * 26 + 52 * 52)* 3、85]データの1次元

(13 * 13 + 26 * 26 + 52 * 52 * 3)それは何ですか?合計でいくつの検出センターがありますか?3を掛けると、各センターに3種類の前のボックスがあります。その場合、(13 * 13 + 26 * 26 + 52 * 52)* 3は、チェックボックスの結果が非常に多いことを意味します。

85とは何ですか。これは、上記の13 * 13、26 * 26、または512 * 512の特徴マップ上の点の特徴値の寸法です。この次元はどのようにして生まれますか?ネットワーク検出ターゲットには80のカテゴリがあり、ポイントに対応する検出フレームには各カテゴリの信頼性に対応する80の確率値があり、各ポイントの検出フレームには4つの値がありますフレームの位置(X、y、w、h)、およびこのボックスの1つの信頼水準。この場合、この点に対応するボックスの固有値は(1 + 4 + 80)= 85次元です。

申し訳ありませんが、cfgファイルで独自のデータトレーニングのためにこの値を変更する必要があるためです。

3.独自のデータセットをトレーニングする手順:

1.データセットを準備します。最初に、yolov3に必要なデータセットがどのように見えるかを理解します。率直に言って、それは写真がラベルファイルに対応することを意味します。画像の山とそれに対応するファイルの山は、画像データセットとラベルデータセットを形成します。ラベルデータセット名は、画像名と1対1で対応します。ラベルデータセットの内容は、カテゴリラベルターゲットフレームxセンター、ターゲットフレームyセンター、ターゲットフレーム幅値、ターゲットフレーム高さ値です。前のカテゴリ番号は直接01 2 3 4 ....などであることに注意してください。後者の値は、浮動小数点値を幅または高さで割った値です。下の写真はとても実用的です。

早く始めて効果を見るために。既製のデータセットを直接ダウンロードします。CCTSDBデータセットを使用します。プログラムを使用してボックスを読み取り、上の図のman007.txtテキストのフォームに書き込みます。

コードは投稿するのに不便で、関数について話すのはとても簡単です。CCTSDBデータセットを読み取り、各画像を読み取り、対応するjsonファイルを読み取り、カテゴリとボックスを読み取ります。カテゴリには0 1 2 ..の番号が付けられ、ボックスデータは上の図に従って計算されます。列に書き込まれます。例:

0 0.669 0.5785714285714286 0.032 0.08285714285714285

1.1テキストファイルを準備します:  train.txt test.txt val.txtlablesテキストファイル

train.txtで、データセットの下に画像の名前を記録します。これと同様に、データセットの画像は/ data / images /ディレクトリに保存されます。

BloodImage_00091
BloodImage_00156
BloodImage_00389
BloodImage_00030
BloodImage_00124
BloodImage_00278
BloodImage_00261

test.txt、表面フォーマットと同じ、内容はテストされるグラフのファイル名です

BloodImage_00258
BloodImage_00320
BloodImage_00120

val.txt、顔の形式と同じ、コンテンツは検証セット内の画像のファイル名です

BloodImage_00777
BloodImage_00951

ラベルタイプのテキスト。画像内の各画像は、次の形式のラベルに関するテキストに対応し、名前はBloodImage_00091.txtに似ています。

0 0.669 0.5785714285714286 0.032 0.08285714285714285

ラベルのテキストは、上記のコードの/ data / lables /に統合されています

1.2 rbc.dataファイルを準備し、ファイル名を自由に設定します。パラメータを入力するときは、このファイル名に従ってプログラムを入力することを忘れないでください。内容は次のとおりです。

1つ目はカテゴリの数、以下はトレーニングに参加している写真のパス、テストに参加している写真、および各カテゴリの名前のテキストパスです。

classes=4
train=data/train.txt
valid=data/test.txt
names=data/rbc.names
backup=backup/
eval=coco

1.3 rbc.namesファイルを準備し、ファイル名を自由に設定します。パラメータを入力するときは、このファイル名に従ってプログラムを入力することを忘れないでください。内容は次のとおりです。

怠惰な場合は、a、b、c、dと書いて、自分のカテゴリに応じて変更するだけの4種類のタイプ。

a
b
c
d

 

1.4画像データを準備し、トレーニング画像を画像に入れ、テスト画像をサンプルに入れます。画像の数字は、ラベルのテキストに1対1で対応しています。

最終的なストレージ構造は、データフォルダの下にあるこれと同様です。

                                                         

2. cfgファイルを変更します。使用するモデルを決定してから、どのcfgファイルを変更します。たとえば、トレーニングにyolov3を使用する場合は、cfgフォルダーに移動してyolov3.cfgを見つけて変更します。変更したのは、カテゴリとフィルタ。フィルタはカテゴリの数に関連しているため、値。yolov3のネットワーク構造を見ると、3つの変更が必要であることがわかります。その他、アンカーのサイズなど。元のフレームが検出対象のターゲットと大幅に異なる場合は、アンカーのセットを再クラスター化して計算することをお勧めします。

classes = 4


#filters=3 * (5 + classes )
filters= 27  #3 * (5 + 4)

アンカーを変更します。トレーニングセットの内容が画像と異なる場合は、変更する必要があります。アンカーを計算するためのコードは次のとおりです。グレートゴッドコードを引用する

# -*- coding: utf-8 -*-
import numpy as np
import random
import argparse
import os
#参数名称
parser = argparse.ArgumentParser(description='使用该脚本生成YOLO-V3的anchor boxes\n')
parser.add_argument('--input_annotation_txt_dir',required=True,type=str,help='输入存储图片的标注txt文件(注意不要有中文)')
parser.add_argument('--output_anchors_txt',required=True,type=str,help='输出的存储Anchor boxes的文本文件')
parser.add_argument('--input_num_anchors',required=True,default=6,type=int,help='输入要计算的聚类(Anchor boxes的个数)')
parser.add_argument('--input_cfg_width',required=True,type=int,help="配置文件中width")
parser.add_argument('--input_cfg_height',required=True,type=int,help="配置文件中height")
args = parser.parse_args()
'''
centroids 聚类点 尺寸是 numx2,类型是ndarray
annotation_array 其中之一的标注框
'''
def IOU(annotation_array,centroids):
    #
    similarities = []
    #其中一个标注框
    w,h = annotation_array
    for centroid in centroids:
        c_w,c_h = centroid
        if c_w >=w and c_h >= h:#第1中情况
            similarity = w*h/(c_w*c_h)
        elif c_w >= w and c_h <= h:#第2中情况
            similarity = w*c_h/(w*h + (c_w - w)*c_h)
        elif c_w <= w and c_h >= h:#第3种情况
            similarity = c_w*h/(w*h +(c_h - h)*c_w)
        else:#第3种情况
            similarity = (c_w*c_h)/(w*h)
        similarities.append(similarity)
    #将列表转换为ndarray
    return np.array(similarities,np.float32) #返回的是一维数组,尺寸为(num,)
 
'''
k_means:k均值聚类
annotations_array 所有的标注框的宽高,N个标注框,尺寸是Nx2,类型是ndarray
centroids 聚类点 尺寸是 numx2,类型是ndarray
'''
def k_means(annotations_array,centroids,eps=0.00005,iterations=200000):
    #
    N = annotations_array.shape[0]#C=2
    num = centroids.shape[0]
    #损失函数
    distance_sum_pre = -1
    assignments_pre = -1*np.ones(N,dtype=np.int64)
    #
    iteration = 0
    #循环处理
    while(True):
        #
        iteration += 1
        #
        distances = []
        #循环计算每一个标注框与所有的聚类点的距离(IOU)
        for i in range(N):
            distance = 1 - IOU(annotations_array[i],centroids)
            distances.append(distance)
        #列表转换成ndarray
        distances_array = np.array(distances,np.float32)#该ndarray的尺寸为 Nxnum
        #找出每一个标注框到当前聚类点最近的点
        assignments = np.argmin(distances_array,axis=1)#计算每一行的最小值的位置索引
        #计算距离的总和,相当于k均值聚类的损失函数
        distances_sum = np.sum(distances_array)
        #计算新的聚类点
        centroid_sums = np.zeros(centroids.shape,np.float32)
        for i in range(N):
            centroid_sums[assignments[i]] += annotations_array[i]#计算属于每一聚类类别的和
        for j in range(num):
            centroids[j] = centroid_sums[j]/(np.sum(assignments==j))
        #前后两次的距离变化
        diff = abs(distances_sum-distance_sum_pre)
        #打印结果
        print("iteration: {},distance: {}, diff: {}, avg_IOU: {}\n".format(iteration,distances_sum,diff,np.sum(1-distances_array)/(N*num)))
        #三种情况跳出while循环:1:循环20000次,2:eps计算平均的距离很小 3:以上的情况
        if (assignments==assignments_pre).all():
            print("按照前后两次的得到的聚类结果是否相同结束循环\n")
            break
        if diff < eps:
            print("按照eps结束循环\n")
            break
        if iteration > iterations:
            print("按照迭代次数结束循环\n")
            break
        #记录上一次迭代
        distance_sum_pre = distances_sum
        assignments_pre = assignments.copy()
if __name__=='__main__':
    #聚类点的个数,anchor boxes的个数
    num_clusters = args.input_num_anchors
    #索引出文件夹中的每一个标注文件的名字(.txt)
    names = os.listdir(args.input_annotation_txt_dir)
    #标注的框的宽和高
    annotations_w_h = []
    for name in names:
        txt_path = os.path.join(args.input_annotation_txt_dir,name)
        #读取txt文件中的每一行
        f = open(txt_path,'r')
        for line in f.readlines():
            line = line.rstrip('\n')
            w,h = line.split(' ')[3:]#这时读到的w,h是字符串类型
            #eval()函数用来将字符串转换为数值型
            annotations_w_h.append((eval(w),eval(h)))
        f.close()
        #将列表annotations_w_h转换为numpy中的array,尺寸是(N,2),N代表多少框
        annotations_array = np.array(annotations_w_h,dtype=np.float32)
    N = annotations_array.shape[0]
    #对于k-means聚类,随机初始化聚类点
    random_indices = [random.randrange(N) for i in range(num_clusters)]#产生随机数
    centroids = annotations_array[random_indices]
    #k-means聚类
    k_means(annotations_array,centroids,0.00005,200000)
    #对centroids按照宽排序,并写入文件
    widths = centroids[:,0]
    sorted_indices = np.argsort(widths)
    anchors = centroids[sorted_indices]
    #将anchor写入文件并保存
    f_anchors = open(args.output_anchors_txt,'w')
    #
    for anchor in  anchors:
        f_anchors.write('%d,%d'%(int(anchor[0]*args.input_cfg_width),int(anchor[1]*args.input_cfg_height)))
        f_anchors.write('\n')

実行ステートメントは次のとおりです。

python kmean.py --input_annotation_txt_dir data/labels --output_anchors_txt 123456.txt --input_num_anchors 9 --input_cfg_width 640 --input_cfg_height 320

結果のファイルは次のとおりです。

12,15
14,20
18,25
24,32
24,18
33,44
39,28
59,49
115,72

cfgに書き込む

3.コードを変更します。

ここにはさらに多くの落とし穴があります。たとえば、train.pyにハイパーパラメータリストを書き込み、cfgの一部の値設定は有効になりません。

train.pyファイルのバッチサイズを変更したい。デフォルト16..。

parser.add_argument('--batch-size', type=int, default=16)  # effective bs = batch_size * accumulate = 16 * 4 = 64

単一ターゲット検出かマルチターゲット検出設定かなど、他にも多くの設定があります。

parser.add_argument('--single-cls', action='store_false', help='train as single-class dataset')

最適化方法はsgdまたはadamを選択します

parser.add_argument('--adam', action='store_true', help='use adam optimizer')

学習率、アダムを使用する場合、トレーニング効果の損失が非常に遅く、常に大きいように見える場合は、この行をオンにして学習率を下げるだけです。

#hyp['lr0'] *= 0.1  # reduce lr (i.e. SGD=5E-3, Adam=5E-4)

重要な質問:上記のコードで設定した後、一部の設定が有効にならない。

たとえば、デフォルトでシングルターゲット検出になっていますが、マルチターゲット検出に変更しましたが、トレーニングはまだ正しくありませんでしたが、後でパラメータ値が有効にならなかったことがわかり、最終的に強制的に有効にしました。

4.トレーニング:自分の裁量で入力を変更します

python train.py --data data/rbc.data --cfg cfg/yolov3.cfg --epochs 2000

共有トレーニングは中断され、ウェイトファイルを自動的に保存するか、自分で転送してから、ウェイトフォルダに配置します。コードload_darknet_weightsは、次のトレーニングの一部です。最後のトレーニングのウェイトファイルを読み取り、その後、トレーニングを続けます。

elif len(weights) > 0:  # darknet format
        # possible weights are '*.weights', 'yolov3-tiny.conv.15',  'darknet53.conv.74' etc.
        load_darknet_weights(model, weights)

5.トレーニングで最も一般的な間違い

ビデオメモリを爆発させるための変更方法は、batchsizeのサイズを小さくすることです。

事前トレーニングモデルが内部に読み込まれ、パスをダウンロードして、パラメーター設定に従って配置できます。たとえば、yolov3に対応するyolov3.weightsファイル

6.予測:

python detect.py --cfg cfg/yolov3-tiny.cfg --weights weights/best.pt

非最大値抑制を行った後、次の文で予測結果が得られます。

pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres,multi_label=False, 
                           classes=opt.classes, agnostic=opt.agnostic_nms)

コードでこの文を見つけてください。たとえば、図に2つのターゲットがある場合、predはリストであり、1 * 6配列はテスト結果です。最初の4桁は座標を格納し、5桁目は信頼水準を格納し、6桁目は次の形式でカテゴリ番号を格納します。明らかに、これらはすべて最初のカテゴリに属します...座標に注意する必要があります。必須です。ズーム上元の画像に対応

tensor([[ 74.13127, 203.66556, 103.19365, 216.29456,   0.72875,   1.00000],
        [255.31650, 123.80228, 284.67999, 136.11815,   0.61970,   1.00000]],
        device='cuda:0')

予測結果のボックスボックスは元の画像のサイズに拡大され、文は次のようになります。ストレージ形式は、(x0、y0、x1、y1)左上隅の座標と右下隅の座標です。

 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()

 

発生したピットを予測します。1台はトレーニング用、もう1台はテスト用の2台のコンピューターで作業すると、エラーが発生します。

RuntimeError: Error(s) in loading state_dict for Darknet

理由:異なるバージョンのpytorchによって導入されたエラー

変更方法:detect.pyの読み込みモデル部分を変更します。原則は深層学習には行きませんでした。偉大な神の実践を参照してください。

将model.load_state_dict(torch.load(weights, map_location=device)['model'])
改为:
model.load_state_dict(torch.load(weights, map_location=device)['model'], False)

7. opencvを使用して調整するのはクールではありませんか?

1.詳細は参考文献5を参照してください。持ち運びます。エラーがあります。直接使用すると、テスト結果の信頼性が非常に高くなります。ボックスとは何ですか?O(∩_∩)O、変更されました上記のトレーニングの結果はbest.ptであり、次のvs2017プロジェクトは.weightsファイルと呼ばれます。変換メソッドコードがあり、modle.pyの下にsave_weights関数があり、それを使用して直接変換できます。設定した変換後、best.ptはconverted.weightsになります。残りは絶対パスなので、特定のファイルを自分で読み取ることができます。modle.pyの最後にこれを追加して、ptファイルをweightsファイルに変換します。

if __name__ == '__main__':
	cfg='cfg/yolov3.cfg'
	weights='last136.pt'
	model = Darknet(cfg)
	if weights.endswith('.pt'):  # if PyTorch format
		model.load_state_dict(torch.load(weights, map_location='cpu')['model'], False)
		save_weights(model, path='converted.weights', cutoff=-1)
		print("Success: converted '%s' to 'converted.weights'" % weights)

2.次の画像のスケーリング方法は、yolov3の方法と矛盾していることに注意してください。これは変更する必要があります。私は怠惰で、変更しませんでした。変更がない場合、ターゲットを検出できません1280 * 720の画像を使用し、512に拡大縮小しました。その結果、拡大縮小された画像は正確に512 * 288になり、32の倍数になります。ズームの目的は、画像の長さと幅を32の倍数にズームすることであり、元の画像を変更することはできません(変形は許可されていません)。通常、行または列を拡大してから、いずれかの方向を入力し、32の倍数を入力する必要があります。コードを書いたのですが、突然、必要ないことに気づきました。それを付けて、記入してください。

 

void YoloResize(Mat in, Mat &out)
{
	int w = in.cols;
	int h = in.rows;
	int target_w = 512;
	int target_h = 512;
	float ratio0 = (float)target_w / w;
	float ratio1 = (float)target_h / h;
	float scale = min(ratio0, ratio1);//转换的最小比例

	//保证长或宽,至少一个符合目标图像的尺寸
	int nw = int(w * scale);
	int nh = int(h * scale);
	//缩放图像
	cv::resize(in, out, cv::Size(nw, nh), (0, 0),(0, 0),cv::INTER_CUBIC);
	//设置输出图像大小,凑足32的倍数。将缩放好的图像放在输出图中间。
	if (ratio0 <= ratio1)//
	{
		//上下填充
		int addh = nh % 32;
		int newh = nh + addh;
	}
	else
	{
		//左右填充
	}
}

 

完全な呼び出しコードはここにあります

// This code is written at BigVision LLC.
//It is subject to the license terms in the LICENSE file found in this distribution and at http://opencv.org/license.html

#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>


using namespace cv;
using namespace dnn;
using namespace std;

// Initialize the parameters
float confThreshold = 0.5; // Confidence threshold
float nmsThreshold = 0.4;  // Non-maximum suppression threshold
int inpWidth = 512;  // Width of network's input image
int inpHeight = 192; // Height of network's input image
vector<string> classes;

// Remove the bounding boxes with low confidence using non-maxima suppression
void postprocess(Mat& frame, const vector<Mat>& out);

// Draw the predicted bounding box
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);

// Get the names of the output layers
vector<String> getOutputsNames(const Net& net);

int main(int argc, char** argv)
{

//*
	string classesFile = "E:\\LL\\rbc.names";
	ifstream ifs(classesFile.c_str());
	string line;
	while (getline(ifs, line)) classes.push_back(line);

	// Give the configuration and weight files for the model
	String modelConfiguration = "E:\\LL\\yolov3_new.cfg";
	String modelWeights = "E:\\LL\\converted.weights";

	// Load the network
	Net net = readNetFromDarknet(modelConfiguration, modelWeights);
	net.setPreferableBackend(DNN_BACKEND_OPENCV);
	net.setPreferableTarget(DNN_TARGET_CPU);

	// Open a video file or an image file or a camera stream.
	string str, outputFile;
	//VideoCapture cap("E:\\SSS.mp4");
	VideoWriter video;
	Mat frame, blob;



	// Create a window
	static const string kWinName = "Deep learning object detection in OpenCV";
	namedWindow(kWinName, WINDOW_NORMAL);

	// Process frames.
	while (waitKey(1) != 27)
	{
		// get frame from the video
		//cap >> frame;

		frame = imread("E:\\LL\\1.jpg");

		// Stop the program if reached end of video
		if (frame.empty()) {
			//waitKey(3000);
			break;
		}
		// Create a 4D blob from a frame.
		cout << "inpWidth = " << inpWidth << endl;
		cout << "inpHeight = " << inpHeight << endl;
		blobFromImage(frame, blob, 1 / 255.0, cv::Size(inpWidth, inpHeight), Scalar(0, 0, 0), true, false);

		//Sets the input to the network
		net.setInput(blob);

		// Runs the forward pass to get output of the output layers
		vector<Mat> outs;
		net.forward(outs, getOutputsNames(net));

		// Remove the bounding boxes with low confidence
		postprocess(frame, outs);

		// Put efficiency information. The function getPerfProfile returns the overall time for inference(t) and the timings for each of the layers(in layersTimes)
		vector<double> layersTimes;
		double freq = getTickFrequency() / 1000;
		double t = net.getPerfProfile(layersTimes) / freq;
		string label = format("Inference time for a frame : %.2f ms", t);
		putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255));

		// Write the frame with the detection boxes
		Mat detectedFrame;
		frame.convertTo(detectedFrame, CV_8U);

		imshow(kWinName, frame);
		waitKey(100000);
	}

	//cap.release();

	
	//*/
	return 0;
}

// Remove the bounding boxes with low confidence using non-maxima suppression
void postprocess(Mat& frame, const vector<Mat>& outs)
{
	vector<int> classIds;
	vector<float> confidences;
	vector<Rect> boxes;

	for (size_t i = 0; i < outs.size(); ++i)
	{
		// Scan through all the bounding boxes output from the network and keep only the
		// ones with high confidence scores. Assign the box's class label as the class
		// with the highest score for the box.
		float* data = (float*)outs[i].data;
		for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols)
		{
			Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
			Point classIdPoint;
			double confidence;
			// Get the value and location of the maximum score
			minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
			if (confidence > 0)
			{
				confidence = confidence;
			}
			if (confidence > confThreshold)
			{
				int centerX = (int)(data[0] * frame.cols);
				int centerY = (int)(data[1] * frame.rows);
				int width = (int)(data[2] * frame.rows);
				int height = (int)(data[3] * frame.cols);
				int left = centerX - width / 2;
				int top = centerY - height / 2;

				classIds.push_back(classIdPoint.x);
				confidences.push_back((float)confidence);
				boxes.push_back(Rect(left, top, width, height));
			}
		}
	}

	// Perform non maximum suppression to eliminate redundant overlapping boxes with
	// lower confidences
	vector<int> indices;
	NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
	for (size_t i = 0; i < indices.size(); ++i)
	{
		int idx = indices[i];
		Rect box = boxes[idx];
		drawPred(classIds[idx], confidences[idx], box.x, box.y,
			box.x + box.width, box.y + box.height, frame);
	}
}

// Draw the predicted bounding box
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)
{
	//Draw a rectangle displaying the bounding box
	rectangle(frame, Point(left, top), Point(right, bottom), Scalar(255, 178, 50), 3);

	//Get the label for the class name and its confidence
	string label = format("%.2f", conf);
	if (!classes.empty())
	{
		CV_Assert(classId < (int)classes.size());
		label = classes[classId] + ":" + label;
	}

	//Display the label at the top of the bounding box
	int baseLine;
	Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
	top = max(top, labelSize.height);
	rectangle(frame, Point(left, top - round(1.5*labelSize.height)), Point(left + round(1.5*labelSize.width), top + baseLine), Scalar(255, 255, 255), FILLED);
	putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 0), 1);
}

// Get the names of the output layers
vector<String> getOutputsNames(const Net& net)
{
	static vector<String> names;
	if (names.empty())
	{
		//Get the indices of the output layers, i.e. the layers with unconnected outputs
		vector<int> outLayers = net.getUnconnectedOutLayers();

		//get the names of all the layers in the network
		vector<String> layersNames = net.getLayerNames();

		// Get the names of the output layers in names
		names.resize(outLayers.size());
		for (size_t i = 0; i < outLayers.size(); ++i)
			names[i] = layersNames[outLayers[i] - 1];
	}
	return names;
}

最後の結果グラフを見てください

検出対象は制限速度カードです。

8.すべての速度:openvino加速方式も付属しています。

openvinoはダークネットをサポートしていないようですので、それを変換する方法を見つけてください。続行~~

https://www.cnblogs.com/jsxyhelu/p/11340822.html マークを付ける

 


参照:

1.https    //blog.csdn.net/zhangping1987/article/details/84942680アンカーの計算

2.https ://blog.csdn.net/sinat_34054843/article/details/88046041   インポートモデルエラーソリューション

3. https://codeload.github.com/zqfang/YOLOv3_CPP/zip/masteryolov3   のC ++コード

4.   opencv4.0のインストール時の、https: //blog.csdn.net/sue_kong/article/details/104401008エラー処理

5. https://blog.csdn.net/zmdsjtu/article/details/81913927  opencvは、コンパイルされたネットワークの重みを呼び出して予測を行います

6. 学習率についてhttps://blog.csdn.net/hzqgangtiexia/article/details/80509211

7.https ://www.cnblogs.com/lvdongjie/p/11270447.html も学習率です

 

つづく...

 

商品の持参:yolov3損失関数https://www.optbbs.com/thread-5590827-1-1.html

yolov3損失関数https://www.cnblogs.com/pprp/p/12590801.html

https://www.cnblogs.com/king-lps/p/9497836.html  はフォーカルロスについて説明しています

 

おすすめ

転載: blog.csdn.net/gbz3300255/article/details/106276897