darknet目标检测之yolov3、4前后处理过程

在将darknet训练好的yolov3、v4转换成mxnet中遇到的一些问题在这里做个总结
对齐主要是三部分

  1. 前处理
  2. 网络前向后的输出
  3. 后处理

前处理

在前处理中darknet主要是将图片读取后放入内存中,放入的顺序为RRR…GGG…BBB…
在darkent项目中的detector.c中将图片保存下来,代码如下:

FILE *fptr;
char output_file_name[1000];
sprintf(output_file_name, "./img_after_preprocess.txt");
fptr = fopen(output_file_name,"w");
for (int index = 0; index < sized.c*sized.w*sized.h; index++) {
    fprintf(fptr,"%f\n",sized.data[index]);
}
fclose(fptr);

在python中将保存好的txt文件转换成图片,代码如下:

import cv2 
import os
import numpy as np
import pdb 
img = np.loadtxt("./img_after_preprocess.txt")
img *= 255 
 
img_r = img[:608*608].reshape([608, 608, 1]) 
img_g = img[608*608:608*608*2].reshape([608, 608, 1]) 
img_b = img[608*608*2:608*608*3].reshape([608, 608, 1]) 
img_out = np.concatenate([img_b, img_g, img_r], axis=-1) #这里需要注意opencv存图片的格式为bgr
cv2.imwrite("test.jpg", img_out)
~               

为了方便做对齐、消除darknet、python的读图、resize的区别,通常我们会使用所有像素为255的矩阵当作网络输入,经过前处理后输入网络的矩阵元素都为1,具体的操作代码在darknet框架下如下:

for(int index = 0; index < sized.c*sized.w*sized.h; index++){
  sized.data[index] = 1;
}

网络前向后的输出

修改darknet下network.c文件的detection *make_network_boxes(network *net, float thresh, int *num)函数,使其将网络的每一层结果保存到文件中,并在python中对每一层的结果求sum对齐,python代码在此处不做展示。

 FILE *fptr;

 int i;
 layer l = net->layers[net->n - 1];
 for (i = 0; i < net->n; ++i) {
     layer l_tmp = net->layers[i];
     char output_file_name[1000];
     sprintf(output_file_name, "./darknet_output/test_layer%d.txt", i);
     fptr = fopen(output_file_name,"w");
     for(int index_i=0; index_i < l_tmp.out_c*l_tmp.out_w*l_tmp.out_h; index_i++) {
         fprintf(fptr,"%f\n",l_tmp.output[index_i]);
     }
     fclose(fptr);
     }
   }

需要注意的是yolov4.cfg中yolo层有个scale_x_y的参数,此参数为了解决yolo层中预测grid sensitivity的问题,主要的是在每层的yolo的x、y上乘以一个系数,此步骤能带来大约2%的map提升。需要强调的是darknet中每一层yolo层的顺序排序为xxxyyywwwhhhCCCc1c1c1c2c2c2c2###xxxyyywwwhhhCCCc1c1c1c2c2c2c2###xxxyyywwwhhhCCCc1c1c1c2c2c2c2…
假设每一层yolo对应有三个anchor boxes,###分隔的是不同anchor
关于scale_x_y参数的解释,参考:alexeyAB对于scale_x_y参数的解释

以下为python解析yolo层的步骤,假设yolo层的输出为[1,18,76,76]

# x.shape = (1, 18, 76, 76) assume feature map size is 76 * 76
x = x.reshape([-1, self.num_boxes * self.bbox_attrs, self.feature_size * self.feature_size]) # x.shape = (1, 18, 5776)
x = F.transpose(x, [0, 2, 1]) # x.shape = (1, 5776, 18) 
x = x.reshape([-1, self.feature_size * self.feature_size * self.num_boxes, self.bbox_attrs]) # x.shape = (1, 17328, 6)   
xy_pred = F.sigmoid(x.slice_axis(begin=0,end=2,axis=-1)) #xy为相对于左上角的偏移,先经过sigmoid变成0-1
xy_pred = xy_pred * self.scale - 0.5*(self.scale - 1.0) #在这里对xy乘以sccale
xy_pred = (xy_pred + x_y_offset) / 76 # 在这里将xy还原成对应特征图的上的相对坐标 0-1
wh_pred = x.slice_axis(begin=2,end=4,axis=-1) 
wh_pred = nd.exp(wh_pred) * anchors / input_dim # 在这里将wh还原成相对坐标0-1
score_pred = F.sigmoid(x.slice_axis(begin=4, end=5, axis=-1)) 
cls_pred = F.sigmoid(x.slice_axis(begin=5,end=None, axis=-1))
output = F.concat(xy_pred, wh_pred, score_pred, cls_pred, dim=-1)

此时矩阵的数据排列为:
左上角第一个bbox
x,y,w,h,C,c1 # anchor1
x,y,w,h,C,c1 # anchor2
x,y,w,h,C,c1 # anchor3
左上角第二个bbox
x,y,w,h,C,c1 # anchor1
x,y,w,h,C,c1 # anchor2
x,y,w,h,C,c1 # anchor3

17328

你可能感兴趣的:(深度学习,python)