YOLO目標檢測快速上手

介紹

圖片描述

YOLO是基於深度學習端到端的實時目標檢測系統,YOLO將目標區域預測和目標類別預測整合於單個神經網絡模型中,實現在準確率較高的情況下快速目標檢測與識別,更加適合現場應用環境。本案例,我們快速實現一個視頻目標檢測功能,實現的具體原理我們將在單獨的文章中詳細介紹。

下載編譯

我們首先下載Darknet開發框架,Darknet開發框架是YOLO大神級作者自己用C語言編寫的開發框架,支持GPU加速,有兩種下載方式:

  1. 下載Darknet壓縮包
  2. git clone https://github.com/pjreddie/darknet

圖片描述

下載後,完整的文件內容,如下圖所示:

圖片描述

編譯:

cd darknet
# 編譯
make

圖片描述

編譯後的文件內容,如下圖所示:

圖片描述

下載權重文件

我們這裏下載的是“yolov3”版本,大小是200多M,“yolov3-tiny”比較小,30多M。

wget https://pjreddie.com/media/files/yolov3.weights

下載權重文件後,文件內容如下圖所示:

圖片描述

上圖中的“yolov3-tiny.weights”,"yolov2-tiny.weights"是我單獨另下載的。

C語言預測

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

圖片描述

如圖所示,我們已經預測出三種類別以及對應的概率值。模型輸出的照片位於darknet根目錄,名字是“predictions.jpg”,如下圖所示:

圖片描述

讓我們打開模型輸出照片看下:

圖片描述

Python語言預測

我們首先需要將“darknet”文件夾內的“libdarknet.so”文件移動到“darknet/python”內,完成後如下圖所示:

圖片描述

我們將使用Darknet內置的“darknet.py”,進行預測。預測之前,我們需要對文件進行修改:

圖片描述

  1. 默認py文件基於python2.0,所以對於python3.0及以上需要修改print
  2. 由於涉及到python和C之間的傳值,所以字符串內容需要轉碼
  3. 使用絕對路徑

修改完成後,如下圖所示:

圖片描述

打開“darknet/cfg/coco.data”文件,將“names”也改爲絕對路徑(截圖內沒有修改,讀者根據自己的實際路徑修改):

圖片描述

我們可以開始預測了,首先進入“darknet/python”然後執行“darknet.py”文件即可:

圖片描述

結果如下圖所示:

圖片描述

對模型輸出的結果做個簡單的說明,如:

# 分別是:類別,識別概率,識別物體的X座標,識別物體的Y座標,識別物體的長度,識別物體的高度
(b'dog', 0.999338686466217, (224.18377685546875, 378.4237060546875, 178.60214233398438, 328.1665954589844)

視頻檢測

from ctypes import *
import random
import cv2
import numpy as np


def sample(probs):
    s = sum(probs)
    probs = [a/s for a in probs]
    r = random.uniform(0, 1)
    for i in range(len(probs)):
        r = r - probs[i]
        if r <= 0:
            return i
    return len(probs)-1

def c_array(ctype, values):
    arr = (ctype*len(values))()
    arr[:] = values
    return arr

class BOX(Structure):
    _fields_ = [("x", c_float),
                ("y", c_float),
                ("w", c_float),
                ("h", c_float)]

class DETECTION(Structure):
    _fields_ = [("bbox", BOX),
                ("classes", c_int),
                ("prob", POINTER(c_float)),
                ("mask", POINTER(c_float)),
                ("objectness", c_float),
                ("sort_class", c_int)]


class IMAGE(Structure):
    _fields_ = [("w", c_int),
                ("h", c_int),
                ("c", c_int),
                ("data", POINTER(c_float))]

class METADATA(Structure):
    _fields_ = [("classes", c_int),
                ("names", POINTER(c_char_p))]

lib = CDLL("../python/libdarknet.so", RTLD_GLOBAL)
lib.network_width.argtypes = [c_void_p]
lib.network_width.restype = c_int
lib.network_height.argtypes = [c_void_p]
lib.network_height.restype = c_int

predict = lib.network_predict
predict.argtypes = [c_void_p, POINTER(c_float)]
predict.restype = POINTER(c_float)

set_gpu = lib.cuda_set_device
set_gpu.argtypes = [c_int]

make_image = lib.make_image
make_image.argtypes = [c_int, c_int, c_int]
make_image.restype = IMAGE

get_network_boxes = lib.get_network_boxes
get_network_boxes.argtypes = [c_void_p, c_int, c_int, c_float, c_float, POINTER(c_int), c_int, POINTER(c_int)]
get_network_boxes.restype = POINTER(DETECTION)

make_network_boxes = lib.make_network_boxes
make_network_boxes.argtypes = [c_void_p]
make_network_boxes.restype = POINTER(DETECTION)

free_detections = lib.free_detections
free_detections.argtypes = [POINTER(DETECTION), c_int]

free_ptrs = lib.free_ptrs
free_ptrs.argtypes = [POINTER(c_void_p), c_int]

network_predict = lib.network_predict
network_predict.argtypes = [c_void_p, POINTER(c_float)]

reset_rnn = lib.reset_rnn
reset_rnn.argtypes = [c_void_p]

load_net = lib.load_network
load_net.argtypes = [c_char_p, c_char_p, c_int]
load_net.restype = c_void_p

do_nms_obj = lib.do_nms_obj
do_nms_obj.argtypes = [POINTER(DETECTION), c_int, c_int, c_float]

do_nms_sort = lib.do_nms_sort
do_nms_sort.argtypes = [POINTER(DETECTION), c_int, c_int, c_float]

free_image = lib.free_image
free_image.argtypes = [IMAGE]

letterbox_image = lib.letterbox_image
letterbox_image.argtypes = [IMAGE, c_int, c_int]
letterbox_image.restype = IMAGE

load_meta = lib.get_metadata
lib.get_metadata.argtypes = [c_char_p]
lib.get_metadata.restype = METADATA

load_image = lib.load_image_color
load_image.argtypes = [c_char_p, c_int, c_int]
load_image.restype = IMAGE

rgbgr_image = lib.rgbgr_image
rgbgr_image.argtypes = [IMAGE]

predict_image = lib.network_predict_image
predict_image.argtypes = [c_void_p, IMAGE]
predict_image.restype = POINTER(c_float)


def convertBack(x, y, w, h):
    xmin = int(round(x - (w / 2)))
    xmax = int(round(x + (w / 2)))
    ymin = int(round(y - (h / 2)))
    ymax = int(round(y + (h / 2)))
    return xmin, ymin, xmax, ymax

def array_to_image(arr):
    # need to return old values to avoid python freeing memory
    arr = arr.transpose(2,0,1)
    c, h, w = arr.shape[0:3]
    arr = np.ascontiguousarray(arr.flat, dtype=np.float32) / 255.0
    data = arr.ctypes.data_as(POINTER(c_float))
    im = IMAGE(w,h,c,data)
    return im, arr

def detect(net, meta, image, thresh=.5, hier_thresh=.5, nms=.45):
    im, image = array_to_image(image)
    rgbgr_image(im)
    num = c_int(0)
    pnum = pointer(num)
    predict_image(net, im)
    dets = get_network_boxes(net, im.w, im.h, thresh,
                             hier_thresh, None, 0, pnum)
    num = pnum[0]
    if nms: do_nms_obj(dets, num, meta.classes, nms)

    res = []
    for j in range(num):
        a = dets[j].prob[0:meta.classes]
        if any(a):
            ai = np.array(a).nonzero()[0]
            for i in ai:
                b = dets[j].bbox
                res.append((meta.names[i], dets[j].prob[i],
                           (b.x, b.y, b.w, b.h)))

    res = sorted(res, key=lambda x: -x[1])
    if isinstance(image, bytes): free_image(im)
    free_detections(dets, num)
    return res


if __name__ == "__main__":
    
    cap = cv2.VideoCapture(0)
    ret, img = cap.read()
    fps = cap.get(cv2.CAP_PROP_FPS)
    
    net = load_net(b"/Users/xiaomingtai/darknet/cfg/yolov2-tiny.cfg", b"/Users/xiaomingtai/darknet/yolov2-tiny.weights", 0)
    meta = load_meta(b"/Users/xiaomingtai/darknet/cfg/coco.data")
    cv2.namedWindow("img", cv2.WINDOW_NORMAL)
    
    while(True):
        ret, img = cap.read()
        if ret:
            r = detect(net, meta, img)

            for i in r:
                x, y, w, h = i[2][0], i[2][17], i[2][18], i[2][19]
                xmin, ymin, xmax, ymax = convertBack(float(x), float(y), float(w), float(h))
                pt1 = (xmin, ymin)
                pt2 = (xmax, ymax)
                cv2.rectangle(img, pt1, pt2, (0, 255, 0), 2)
                cv2.putText(img, i[0].decode() + " [" + str(round(i[1] * 100, 2)) + "]", (pt1[0], pt1[1] + 20), cv2.FONT_HERSHEY_SIMPLEX, 1, [0, 255, 0], 4)
            cv2.imshow("img", img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

模型輸出結果:

圖片描述

模型視頻檢測結果:

圖片描述

沒有GPU的條件下還是不要選擇yolov3了,很慢。

總結

本篇文章主要是YOLO快速上手,我們通過很少的代碼就能實現不錯的目標檢測。當然,想熟練掌握YOLO,理解背後的原理是十分必要的,下篇文章將會重點介紹YOLO原理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章