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);
}
編譯後,就可以使用以上代碼使用了。