主頁 >  其他 > Yolov3 和 Yolov3-tiny快速實作目標檢測(TensorFlow2版)

Yolov3 和 Yolov3-tiny快速實作目標檢測(TensorFlow2版)

2021-09-25 15:21:11 其他

文章目錄

  • 前言
  • 一、Yolov3 和 Yolov3-tiny
  • 1.網路結構
      • yolov3-tiny
      • yolov3
  • 二、配置訓練引數
    • 1.目標檢測資料集
    • 2.設定anchor box 和classes
  • 三、 配置訓練程序
  • 四、模型預測
  • 總結
  • 博主的抱怨


前言

上一篇文章 神奇的目標檢測 已經介紹了目標檢測的基礎啦,目標檢測呢,就是在圖片中定位出目標的位置,把它“框”出來就好了,本篇文章使用Yolov3 和Yolov3-tiny,以訓練VOC2007和口罩檢測為例,教大家如何快速的搭建自己的目標檢測平臺,下面是資源鏈接:

內容鏈接
VOC2007 資料集鏈接
戴口罩資料集鏈接
權重檔案鏈接 提取碼:y32m
github專案地址鏈接
完整專案地址(包含所有檔案)鏈接 提取碼 jmpl

一、Yolov3 和 Yolov3-tiny

2018 年,推出了Yolov3,相比于Yolov2 最主要的改進有,一就是加深了網路,使用53層Darknet,二就是采用了FPN(空間金字塔結構),三是使用了focal loss,對于tiny版本來說,只使用了簡單的44層卷積用作普通的特征提取,每個網格點使用兩個anchor boxes(Yolov3三個),所以tiny版本檢測速度是很快的哦~,但檢測效果就…,

1.網路結構

網路結構中包含了很多基礎塊,我們先實作這些基本的塊,然后像搭積木一樣將這些塊給組裝起來,每個塊的用途我已經寫在代碼注釋里了,

 #定義的卷積設定初始化方法和卷積步長和填充方式
@wraps(Conv2D)
def DarknetConv2D(*args, **kwargs):
    """Wrapper to set Darknet parameters for Convolution2D."""
    #定義卷積塊
    darknet_conv_kwargs = {'kernel_regularizer': l2(5e-4)}
    darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides')==(2,2) else 'same'
    darknet_conv_kwargs.update(kwargs)
    return Conv2D(*args, **darknet_conv_kwargs)

def DarknetConv2D_BN_Leaky(*args, **kwargs):
    #定義的卷積塊包含了BN Leaky 激活函式
    """Darknet Convolution2D followed by BatchNormalization and LeakyReLU."""
    no_bias_kwargs = {'use_bias': False}
    no_bias_kwargs.update(kwargs)
    return compose(
        DarknetConv2D(*args, **no_bias_kwargs),
        BatchNormalization(),
        LeakyReLU(alpha=0.1))

def resblock_body(x, num_filters, num_blocks):
    '''A series of resblocks starting with a downsampling Convolution2D'''
    #定義 yolo 主干使用的殘差快
    # Darknet uses left and top padding instead of 'same' mode
    x = ZeroPadding2D(((1,0),(1,0)))(x)
    x = DarknetConv2D_BN_Leaky(num_filters, (3,3), strides=(2,2))(x)
    for i in range(num_blocks):
        y = compose(
                DarknetConv2D_BN_Leaky(num_filters//2, (1,1)),
                DarknetConv2D_BN_Leaky(num_filters, (3,3)))(x)
        x = Add()([x,y])
    return x

def darknet_body(x):
    '''Darknent body having 52 Convolution2D layers'''
    #darknet 53
    #卷積核大小3x3 32 個卷積核
    x = DarknetConv2D_BN_Leaky(32, (3,3))(x)
    x = resblock_body(x, 64, 1)
    x = resblock_body(x, 128, 2)
    x = resblock_body(x, 256, 8)
    x = resblock_body(x, 512, 8)
    x = resblock_body(x, 1024, 4)
    return x

def make_last_layers(x, num_filters, out_filters):
    '''6 Conv2D_BN_Leaky layers followed by a Conv2D_linear layer'''
    # 這里是輸入yolo,制造最后一層的代碼 也就是yolo head
    x = compose(
            DarknetConv2D_BN_Leaky(num_filters, (1,1)),
            DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),
            DarknetConv2D_BN_Leaky(num_filters, (1,1)),
            DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),
            DarknetConv2D_BN_Leaky(num_filters, (1,1)))(x)
    y = compose(
            DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),
            DarknetConv2D(out_filters, (1,1)))(x)
    return x, y

yolov3-tiny

tiny 版本網路結構比較簡單,我們先來看一個圖:
在這里插入圖片描述
網路中就是普通的卷積核和池化,且網路很淺,網路的計算程序如箭頭所示,是不是網路很簡單呀~~~~~,
我們接下來看代碼如何實作,

def tiny_yolo_body(inputs, num_anchors, num_classes):
	#-------------------------------------------------------------------
	# inputs 輸入向量  num_anchors anchor boxes的數量 num_classes 類別數
	#------------------------------------------------------------------
    '''Create Tiny YOLO_v3 model CNN body in keras.'''
    x1 = compose(
            DarknetConv2D_BN_Leaky(16, (3,3)),
            MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
            DarknetConv2D_BN_Leaky(32, (3,3)),
            MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
            DarknetConv2D_BN_Leaky(64, (3,3)),
            MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
            DarknetConv2D_BN_Leaky(128, (3,3)),
            MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
            DarknetConv2D_BN_Leaky(256, (3,3)))(inputs)
    x2 = compose(
            MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
            DarknetConv2D_BN_Leaky(512, (3,3)),
            MaxPooling2D(pool_size=(2,2), strides=(1,1), padding='same'),
            DarknetConv2D_BN_Leaky(1024, (3,3)),
            DarknetConv2D_BN_Leaky(256, (1,1)))(x1)
    y1 = compose(
            DarknetConv2D_BN_Leaky(512, (3,3)),
            DarknetConv2D(num_anchors*(num_classes+5), (1,1)))(x2)

    x2 = compose(
            DarknetConv2D_BN_Leaky(128, (1,1)),
            UpSampling2D(2))(x2)
    y2 = compose(
            Concatenate(),
            DarknetConv2D_BN_Leaky(256, (3,3)),
            DarknetConv2D(num_anchors*(num_classes+5), (1,1)))([x2,x1])

    return Model(inputs, [y1,y2])

DarknetConv2D DarknetConv2D_BN_Leaky 是使用二維卷積定義的塊,可以去代碼里查看,很好理解的,

yolov3

yolov3使用了殘差結構和FPN, 網路較深,結構復雜,我們先來看一下他的整體網路結構:
在這里插入圖片描述
這里使用的FPN(Feature Pyramid Network) 特征金字塔如下圖所示:

在目標檢測中,往往會包含不用大小的目標,多層卷積后,小目標的語意丟失比較嚴重,使用FPN 能有效的利用多層特征資訊 加強淺層小目標的特征新資訊,提升網路的檢測能力,

def yolo_body(inputs, num_anchors, num_classes):
    """Create YOLO_V3 model CNN body in Keras."""
    #------------------------------------------------------------------
	# inputs 輸入向量  num_anchors anchor boxes的數量 num_classes 類別數
	#------------------------------------------------------------------
    darknet = Model(inputs, darknet_body(inputs))
    x, y1 = make_last_layers(darknet.output, 512, num_anchors*(num_classes+5))

    x = compose(
            DarknetConv2D_BN_Leaky(256, (1,1)),
            UpSampling2D(2))(x)
    x = Concatenate()([x,darknet.layers[152].output])
    x, y2 = make_last_layers(x, 256, num_anchors*(num_classes+5))

    x = compose(
            DarknetConv2D_BN_Leaky(128, (1,1)),
            UpSampling2D(2))(x)
    x = Concatenate()([x,darknet.layers[92].output])
    x, y3 = make_last_layers(x, 128, num_anchors*(num_classes+5))
	# yolo head的輸出,
    return Model(inputs, [y1,y2,y3])

代碼中的 make_last_layers 是產生YOLO的輸出層,對于引數 :

 num_anchors*(num_classes+5)

yolo3 每個網格點有3個anchor boxes,num_achors=3 ,每個anchor box都要預測所有的類別,假設我們使用的是Voc2007 有20類別,num_classes=20, 5代表框的p(框中有目標的概率),x_offset、y_offset、h和w 4個值,yolo head 中的輸出維度就為 [batch_size,w,h,3x(20+5)],
到這里YOLO的主干網路解介紹完了,

二、配置訓練引數

1.目標檢測資料集

以VOC 2007 資料集為例,首先來看一下檔案樹:

─VOC2007
    ├─Annotations
    │	└─000005.xml
    │	└─000006.xml
    │	└─xxxx.xml	
    ├─ImageSets
    │  └─Main
    └─JPEGImages
    │	└─000005.jpg
    │	└─000006.jpg
    │	└─xxxx.jpg

每一個xml 包含同名jpg 中目標的位置以及類別,在訓練時,首先要將資料 通過 voc_annotation.py 轉換到記事本中,方便訓練時讀取,記事本形式如下:

VOC2007/JPEGImages/000005.jpg(圖片路徑)98,267,194,383(框的位置) ,1(框中目標的類別)
VOC2007/JPEGImages/000006.jpg(圖片路徑)99,205,198,318(框的位置) ,1(框中目標的類別)

這樣的資料是無法直接和YOLO的輸出進行計算的,那么我們還需要將,這種資料編碼成和yolo head 的格式一樣,才能去計算loss,反向傳播調整引數
通過如下函式將y_ture,轉換成和y_predict 一樣的形式:

def preprocess_true_boxes(true_boxes, input_shape, anchors, num_classes):
    '''Preprocess true boxes to training input format
    Parameters
    ----------
    	true_boxes: array, shape=(m, T, 5)
        Absolute x_min, y_min, x_max, y_max, class_id relative to input_shape.
    input_shape: array-like, hw, multiples of 32
    anchors: array, shape=(N, 2), wh
    num_classes: integer
    Returns
    -------
    y_true: list of array, shape like yolo_outputs, xywh are reletive value

    '''
    assert (true_boxes[..., 4]<num_classes).all(), 'class id must be less than num_classes'
    num_layers = len(anchors)//3 # default setting
    anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]]

    true_boxes = np.array(true_boxes, dtype='float32')
    input_shape = np.array(input_shape, dtype='int32')
    boxes_xy = (true_boxes[..., 0:2] + true_boxes[..., 2:4]) // 2
    boxes_wh = true_boxes[..., 2:4] - true_boxes[..., 0:2]
    true_boxes[..., 0:2] = boxes_xy/input_shape[::-1]
    true_boxes[..., 2:4] = boxes_wh/input_shape[::-1]

    m = true_boxes.shape[0]
    grid_shapes = [input_shape//{0:32, 1:16, 2:8}[l] for l in range(num_layers)]
    y_true = [np.zeros((m,grid_shapes[l][0],grid_shapes[l][1],len(anchor_mask[l]),5+num_classes),
        dtype='float32') for l in range(num_layers)]

    # Expand dim to apply broadcasting.
    anchors = np.expand_dims(anchors, 0)
    anchor_maxes = anchors / 2.
    anchor_mins = -anchor_maxes
    valid_mask = boxes_wh[..., 0]>0

    for b in range(m):
        # Discard zero rows.
        wh = boxes_wh[b, valid_mask[b]]
        if len(wh)==0: continue
        # Expand dim to apply broadcasting.
        wh = np.expand_dims(wh, -2)
        box_maxes = wh / 2.
        box_mins = -box_maxes

        intersect_mins = np.maximum(box_mins, anchor_mins)
        intersect_maxes = np.minimum(box_maxes, anchor_maxes)
        intersect_wh = np.maximum(intersect_maxes - intersect_mins, 0.)
        intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]
        box_area = wh[..., 0] * wh[..., 1]
        anchor_area = anchors[..., 0] * anchors[..., 1]
        iou = intersect_area / (box_area + anchor_area - intersect_area)

        # Find best anchor for each true box
        best_anchor = np.argmax(iou, axis=-1)

        for t, n in enumerate(best_anchor):
            for l in range(num_layers):
                if n in anchor_mask[l]:
                    i = np.floor(true_boxes[b,t,0]*grid_shapes[l][1]).astype('int32')
                    j = np.floor(true_boxes[b,t,1]*grid_shapes[l][0]).astype('int32')
                    k = anchor_mask[l].index(n)
                    c = true_boxes[b,t, 4].astype('int32')
                    y_true[l][b, j, i, k, 0:4] = true_boxes[b,t, 0:4]
                    y_true[l][b, j, i, k, 4] = 1
                    y_true[l][b, j, i, k, 5+c] = 1
    #print(y_true.shape)
    return y_true

資料集放置如下圖所示:
在這里插入圖片描述在這里插入圖片描述

2.設定anchor box 和classes

Yolo 中的anchor boxes 是通過資料集中框的大小通過kmeans聚類而來,yolov3 有三個輸出,每個網格預測3個,所以 Kmeans中的K設定9,如果是tiny版本的話,就設定為6,代碼如下:

import numpy as np
"""
Kmeans 聚類演算法, 根據 資料集中的xml 檔案 聚類出是和目標的anchor boxes
"""
class YOLO_Kmeans:

    def __init__(self, cluster_number, filename):
        self.cluster_number = cluster_number
        self.filename =filename

    def iou(self, boxes, clusters):  # 1 box -> k clusters
        n = boxes.shape[0]
        k = self.cluster_number

        box_area = boxes[:, 0] * boxes[:, 1]
        box_area = box_area.repeat(k)
        box_area = np.reshape(box_area, (n, k))

        cluster_area = clusters[:, 0] * clusters[:, 1]
        cluster_area = np.tile(cluster_area, [1, n])
        cluster_area = np.reshape(cluster_area, (n, k))

        box_w_matrix = np.reshape(boxes[:, 0].repeat(k), (n, k))
        cluster_w_matrix = np.reshape(np.tile(clusters[:, 0], (1, n)), (n, k))
        min_w_matrix = np.minimum(cluster_w_matrix, box_w_matrix)

        box_h_matrix = np.reshape(boxes[:, 1].repeat(k), (n, k))
        cluster_h_matrix = np.reshape(np.tile(clusters[:, 1], (1, n)), (n, k))
        min_h_matrix = np.minimum(cluster_h_matrix, box_h_matrix)
        inter_area = np.multiply(min_w_matrix, min_h_matrix)

        result = inter_area / (box_area + cluster_area - inter_area)
        return result

    def avg_iou(self, boxes, clusters):
        accuracy = np.mean([np.max(self.iou(boxes, clusters), axis=1)])
        return accuracy

    def kmeans(self, boxes, k, dist=np.median):
        box_number = boxes.shape[0]
        distances = np.empty((box_number, k))
        last_nearest = np.zeros((box_number,))
        np.random.seed()
        clusters = boxes[np.random.choice(
            box_number, k, replace=False)]  # init k clusters
        while True:

            distances = 1 - self.iou(boxes, clusters)

            current_nearest = np.argmin(distances, axis=1)
            if (last_nearest == current_nearest).all():
                break  # clusters won't change
            for cluster in range(k):
                clusters[cluster] = dist(  # update clusters
                    boxes[current_nearest == cluster], axis=0)

            last_nearest = current_nearest

        return clusters

    def result2txt(self, data):
        f = open("yolo_anchors1.txt", 'w') # 這里是生存achor后保存的路徑
        row = np.shape(data)[0]
        for i in range(row):
            if i == 0:
                x_y = "%d,%d" % (data[i][0], data[i][1])
            else:
                x_y = ", %d,%d" % (data[i][0], data[i][1])
            f.write(x_y)
        f.close()

    def txt2boxes(self):
        f = open(self.filename, 'r')
        dataSet = []
        for line in f:
            infos = line.split(" ")
            length = len(infos)
            for i in range(1, length):
                width = int(infos[i].split(",")[2]) - \
                    int(infos[i].split(",")[0])
                height = int(infos[i].split(",")[3]) - \
                    int(infos[i].split(",")[1])
                dataSet.append([width, height])
        result = np.array(dataSet)
        f.close()
        return result

    def txt2clusters(self):
        all_boxes = self.txt2boxes()
        result = self.kmeans(all_boxes, k=self.cluster_number)
        result = result[np.lexsort(result.T[0, None])]
        self.result2txt(result)
        print("K anchors:\n {}".format(result))
        print("Accuracy: {:.2f}%".format(
            self.avg_iou(all_boxes, result) * 100))

#通過聚類方法設定資料集中合適的框
if __name__ == "__main__":
    cluster_number =9 #聚類框的個數 6 或者 9
    filename = r"2007_train.txt" # 指定train.txt的路勁
    kmeans = YOLO_Kmeans(cluster_number, filename)
    kmeans.txt2clusters()

當然也可以使用yolo中默認的achor box的大小,
classes.txt 是宣告 你目標中所有的類別,以戴口罩資料集為例

without_mask
with_mask
mask_weared_incorrect

文本中書寫的類別要和你xml 檔案中所寫類別保持一致,才能正確索引,

三、 配置訓練程序

訓練程序需要配置的東西,就是之前的資料準備,輸入模型即可,
訓練過錯記憶體溢位,記得吧batch_size 改小一點,yolo完整版的話一般設定為8比較好
代碼:

def train():
    # 你的 資料集檔案路勁
    train_annotation_path = r"2007_train.txt" # 生存的資料索引txt文本
    val_annotation_path = r"2007_val.txt"

    anchors_path = r"model_data\mask_anchor.txt" # 生成的anchor
    classes_path = r"model_data\mask_classes.txt" #自己資料集的類別
    log_dir = "logs/tiny_log/"
    weights_dir = "weights/"
    class_names = get_classes(classes_path)
    num_classes = len(class_names)
    anchors = get_anchors(anchors_path)

    input_shape = (416, 416)  #  必須是32的 倍數  yolo 的設定

	# tiny 版本
    model = create_tiny_model(
        input_shape=input_shape,
        anchors=anchors,
        num_classes=num_classes,
        freeze_body=2,
        weights_path="model_data\yolov3-tiny.h5",
    )
    ''''
     # yolo v3 的完整版本 ,
    model = create_model(
        input_shape=input_shape,
        anchors=anchors,
        num_classes=num_classes,
        # freeze_body=0,
        weights_path="model_data\yolov3.h5",
    )
    '''
    print(len(model.layers))
    logging = TensorBoard(log_dir=log_dir)
    checkpoint = ModelCheckpoint(
        weights_dir + "ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5",
        monitor="val_loss",
        save_weights_only=True,
        save_best_only=True,
        period=3,
    )
    reduce_lr = ReduceLROnPlateau(monitor="val_loss", factor=0.1, patience=3, verbose=1)
    early_stopping = EarlyStopping(
        monitor="val_loss", min_delta=0, patience=10, verbose=1
    )

    # 讀取資料集對應的 .txt 檔案
    with open(train_annotation_path) as f:
        train_lines = f.readlines()
    with open(val_annotation_path) as f:
        val_lines = f.readlines()
    num_train = len(train_lines)
    num_val = len(val_lines)

    # 配置訓練引數
    Freeze_Train = True
    # ------------------------------------------------------------
    # 先凍結一定網路層進行訓練,這樣訓練比較快 ,得到一個loss穩定的model
    # -------------------------------------------------------------
    if Freeze_Train:
        batch_size = 32
        model.compile(
            optimizer=Adam(1e-3),
            loss={# use custom yolo_loss Lambda layer.
            "yolo_loss": lambda y_true, y_pred: y_pred}
        )
        print("Train on {} samples, val on {} samples, with batch size {}.".format(num_train, num_val, batch_size))
        model.fit(
            data_generator_wrapper(train_lines,batch_size,input_shape,anchors,num_classes),
            steps_per_epoch=max(1,num_train//batch_size),
            validation_data=data_generator_wrapper(val_lines,batch_size,input_shape,anchors,num_classes),
            validation_steps=max(1,num_val//batch_size),
            epochs=50,
            initial_epoch=0,
            callbacks=[logging,checkpoint]
        )
        model.save_weights(weights_dir+'trained_weights_stage_1.h5')
     #-----------------------------------------------------------------
     # 解凍所有層,并調小學習率訓練
     #-----------------------------------------------------------------
    if True:
        for i in range(len(model.layers)): model.layers[i].trainable = True
        model.compile(optimizer=Adam(lr=1e-4), loss={'yolo_loss': lambda y_true, y_pred: y_pred}) # recompile to apply the change
        print('Unfreeze all of the layers.')

        batch_size = 32 # note that more GPU memory is required after unfreezing the body
        print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
        model.fit_generator(data_generator_wrapper(train_lines, batch_size, input_shape, anchors, num_classes),
            steps_per_epoch=max(1, num_train//batch_size),
            validation_data=data_generator_wrapper(val_lines, batch_size, input_shape, anchors, num_classes),
            validation_steps=max(1, num_val//batch_size),
            epochs=100,
            initial_epoch=50,
            callbacks=[logging, checkpoint, reduce_lr, early_stopping])
        model.save_weights(log_dir + 'trained_weights_final.h5')


if __name__=='__main__':
    train()

上述就是訓練程序了,訓練時,
注意:
使用model 時,tiny 和YOLOv3 achor 不一樣,一個是6 類 一個是9類 ,記得更換
tips:訓練過錯先凍結一部分層去訓練,這樣訓練比較快,當損失穩定之后,使用更小的學習率去,趨勢模型收斂更好,
訓練結果如下:
在這里插入圖片描述
可以看出收斂效果還是相當不錯的,,,,

四、模型預測

模型預測,將圖片輸入到保存的模型當中,如果輸出一個跟yolo head 一樣的維度,很顯然這個時候我們是無法獲圖片的類別還有框的,那么需要通過解碼,拿到我們有用的資料,這個作業在專案中的yolo.py 中實作,

#這里不給出全部代碼了,但在預測是,網路的權重檔案 achor boxes 和classes 要保持一直,在檔案中這個位置配置
_defaults = {
        # ----------------------------------
        # 模型路徑, anchor路徑,class 路徑, 
        # sorce 一本設為0.5  置信度閾值 iou 
        #  輸入圖片大小 一般是13 的倍數
        #   gpu 1
        #  遇上維度 不匹配問題  可能是訓練時 忘記讓model_path 和class_path 對應 
        # -----------------------------------
        "model_path": r"logs\yolov3_log\trained_weights_final.h5",
        "anchors_path": "model_data\mask_anchor.txt",
        "classes_path": "model_data\mask_classes.txt",
        "score": 0.3,
        "iou": 0.3,
        "model_image_size": (416, 416),
        "gpu_num": 1, # 這里使用1 ,多gpu 由于TensorFlow 版本問題 我給注解掉了
    }

模型預測完整代碼:

import time

import cv2
import numpy as np
import tensorflow as tf
from PIL import Image
from yolo import YOLO,detect_video
import os
from tqdm import tqdm
def predict():
    #-------------------------------------------------------------
    # 新建 yolo 物件,使用模型權重路徑,以及其他引數,到yolo.py 中更改
    # predict_model 為 img 預測圖片, video  輸入為視頻,記得更改視頻路勁   video_path 為 0 時呼叫攝像頭  為視頻路徑時 讀取視頻
    # predict_model 為 dir_predict 時輸入為存放圖片的路徑 ,預測完成后 放入out_img 使用時記得修改路勁
    # 要預測  指定類別是 ,可以設定好重新訓練模型,或者進入detect_image 修改引數 if predicted_classes='car'
    #--------------------------------------------------------------
    yolo=YOLO()  
    predict_model='dir_predict'

    video_path= 0
    video_save_path=""

    dir_img_input='img/'
    dir_save_path='out_img/'
    if predict_model=='img':
        while(True):
            img=input('Input image filename:')
            try:
                image=Image.open(img)
            except:
                print('Open Image Error! Please Try Again')
                continue
            else:
                out_image=yolo.detect_image(image)
                out_image.show()
    elif predict_model=='video':
        detect_video(yolo,video_path,video_save_path) # 可以獲取fps
    
    elif predict_model=='dir_predict':
        #---------------------------------
        #拿到所有圖片 通過detect image 檢測
        #-------------------------------
        imgs=os.listdir(dir_img_input)
        for img_name in tqdm(imgs):
             if img_name.lower().endswith(('.bmp', '.dib', '.png', '.jpg', '.jpeg', '.pbm', '.pgm', '.ppm', '.tif', '.tiff')):
                image_path  = os.path.join(dir_img_input, img_name)
                image       = Image.open(image_path)
                r_image     = yolo.detect_image(image)
                if not os.path.exists(dir_save_path):
                    os.makedirs(dir_save_path)
                r_image.save(os.path.join(dir_save_path, img_name)) 
    else:
           raise AssertionError("Please specify the correct mode: 'img', 'video', 'dir_predict'.")
if __name__=='__main__':
    predict()

使用方法寫在注釋里了,支持視頻,圖片 檔案夾
檢測結果:
在這里插入圖片描述

總結

目標檢測網路結構,其實跟影像分類差不多,但對資料讀取程序,編碼解碼程序比較復雜,對于這個程序,我掌握不是很多,所以就不在這里講解了,
目標檢測訓練比較難,資料標注比較麻煩,后面可能會出一期視頻,教大家如何配置,所有代碼和資源均會上傳,寫代碼不易,歡迎點贊~

博主的抱怨

哎,太難了,哎~ cv 太卷了,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302705.html

標籤:AI

上一篇:【軟體工具】visual studio 安裝教程

下一篇:python實作地牢迷宮生成

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more