在Darknet框架中,自带的darknet.py可以使用weight、cfg、coco.data(或者voc.data)、coco.names(voc.names),以及在darknet路径下make生成的libdarknet.so(如图1),利用这些文件即可完成图片中的目标检测,并标出检测框。
图1图2 darknet.py的主函数
但是对于检测视频来说,darknet.py中的detect函数,第3个参数是“data/dog.jpg”,是图片带路径的文件名,而opencv读取视频是这样操作的:
cap = cv2.VideoCapture("test_video/cars.mp4")
frame_count = 0
while True:
ret, frame = cap.read()
frame就是读取到的每一帧,而frame的格式是array数组,因此不能直接应用到detect函数中,需要做一个格式转换。
(在修改之前查阅了很多资料,大多都是在darknet的源码中修改,比如,修改image.c文件等,然后再make生一个新的libdarknet.so,但是这样就有点复杂了,而且我修改源码之后出错,所以在darknet.py中修改会很方便)
def array_to_image(arr):
"""
opencv获得的frame是array格式,需要将其转换为image供yolo检测
"""
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
def detect(net, meta, image, thresh=.5, hier_thresh=.5, nms=.45):
# im = load_image(image, 0, 0) #####原始
im = 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):
for i in range(meta.classes):
if dets[j].prob[i] > 0:
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])
free_image(im)
free_detections(dets, num)
return res
cap = cv2.VideoCapture("test_video/cars.mp4")
frame_count = 0
while True:
ret, frame = cap.read()
boxes = detect(net, meta, frame)
得到检测的框boxes之后,就可以为所欲为啦!
没有放完整代码,自己动手实践一下吧,有更高招的欢迎留言!