darknet編譯python接口,並修改輸入Mat圖像

1 編譯so文件

修改./darknet/Makefile

GPU=1
CUDNN=1
CUDNN_HALF=0
OPENCV=1
AVX=0
OPENMP=0
LIBSO=1			# 設爲1,編譯生成so
ZED_CAMERA=0 # ZED SDK 3.0 and above
ZED_CAMERA_v2_8=0 # ZED SDK 2.X

make編譯,或者make -j8

2 python接口封裝

darkne目錄下,已有示例
./darknet/darknet.py
./darknet/darknet_video.py
看着複雜,簡化封裝一下,如下:

#!/usr/bin/python
# -*- coding:utf-8 -*-
from ctypes import *
import math,os,sys,cv2

homePath = os.path.expanduser('~')
darknetPath = os.path.join(homePath, 'darknet')

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),
                **("uc", POINTER(c_float)),	# YOLOv3和YOLOv4不同處,YOLOv4需要,v3不需要**
                **("points", c_int)]		# YOLOv3和YOLOv4不同處,YOLOv4需要,v3不需要**
]

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))]

class darknetDetect:
    def __init__(self, weight_path, cfg_path, data_path):
        self.libdarknetPath = os.path.join(darknetPath, 'libdarknet.so')
        self.lib = CDLL(self.libdarknetPath)
        self.get_network_boxes = self.lib.get_network_boxes
        self.get_network_boxes.argtypes = [c_void_p, c_int, c_int, c_float, c_float, POINTER(c_int), c_int, POINTER(c_int)]
        self.get_network_boxes.restype = POINTER(DETECTION)

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

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

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

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

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

        self.load_image_data = self.lib.load_image_cv_data
        self.load_image_data.argtypes = [c_char_p, c_int, c_int]
        self.load_image_data.restype = IMAGE

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

        if sys.version_info.major != 2:
            cfg_path = cfg_path.encode()
            weight_path = weight_path.encode()
            data_path = data_path.encode()
        self.net = self.load_net(cfg_path, weight_path, 0)
        self.meta = self.load_meta(data_path)

    def detect(self, img, thresh=.5, hier_thresh=.5, nms=.45):
        data_ctypes_ptr = cast(img.ctypes.data, POINTER(c_char))
        im = self.load_image_data(data_ctypes_ptr, img.shape[1], img.shape[0])
        num = c_int(0)
        pnum = pointer(num)
        self.predict_image(self.net, im)
        dets = self.get_network_boxes(self.net, im.w, im.h, thresh, hier_thresh, None, 0, pnum)
        num = pnum[0]
        if (nms): self.do_nms_obj(dets, num, self.meta.classes, nms);
        res = []
        for j in range(num):
            for i in range(self.meta.classes):
                if dets[j].prob[i] > 0:
                    box = dets[j].bbox
                    l = box.x / img.shape[1]
                    t = box.y / img.shape[0]
                    r = box.w / img.shape[1]
                    b = box.h / img.shape[0]
                    res.append((l, t, r, b, dets[j].prob[i], i, self.meta.names[i]))
        self.free_image(im)
        self.free_detections(dets, num)
        return res
if __name__ == "__main__":
    pass

3 修改Mat接口-YOLOv3&YOLOv4

官方demo和命令行,都是輸入圖像路徑,如果想使用Mat類型,需要修改一下源碼再編譯,修改如下
./darknet/image_opencv.cpp

extern "C" image load_image_cv_data(unsigned char *data, int w, int h)
{
	cv::Mat src(cv::Size(w, h), CV_8UC3, data);

	if (!src.data) {
        return make_image(10, 10, 3);
    }
	return  mat_to_image(src);
}

YOLOv4和YOLOv3有些不一樣,後續還要加RGB2BGR

extern "C" image load_image_cv_data(unsigned char *data, int w, int h)
{
	cv::Mat src(cv::Size(w, h), CV_8UC3, data);

	if (!src.data) {
        return make_image(10, 10, 3);
    }
    cv::Mat dst;
    cv::cvtColor(src, dst, cv::COLOR_RGB2BGR);	# 就是這樣rgb2bgr
	return  mat_to_image(src);
}

編譯後,就可以使用以上代碼使用了。

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