版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linmingan/article/details/82252012
yoloV2的预测代码在examples/detector.c中的test_detector函数中。具体步骤为:
1、模型、参数、待检测图片等信息的加载
2、图片resize,这里使用的是letterbox_image函数。与opencv的resize函数不同的是letterbox不会使物体变形。这边是移植到手机端的一个坑。
3、前向传播,获取网络输出,大小为13*13*425(假设,输入为416*416,80类,5个候选框)
4、根据网络预测的候选框与anchor的x,y偏移量和w,h比值,求出候选框的bbox。get_region_boxes函数。
5、利用非极大值抑制去除重叠的候选框
letterbox_image
image letterbox_image(image im, int w, int h)//w,h:要resize的大小
{
int new_w = im.w;
int new_h = im.h;
//计算保持宽高比的新宽高
if (((float)w/im.w) < ((float)h/im.h)) {
new_w = w;
new_h = (im.h * w)/im.w;
} else {
new_h = h;
new_w = (im.w * h)/im.h;
}
//直接resize
image resized = resize_image(im, new_w, new_h);
//创建一个大小为w*h的空图片
image boxed = make_image(w, h, im.c);
//将空图片用【0.5,0.5,0.5】填充
fill_image(boxed, .5);
//int i;
//for(i = 0; i < boxed.w*boxed.h*boxed.c; ++i) boxed.data[i] = 0;
//将resized图片填充到空图片中。
embed_image(resized, boxed, (w-new_w)/2, (h-new_h)/2);
free_image(resized);
return boxed;
}
get_region_boxes
代码在src/region_layer.c里面的get_region_boxes函数里,注意不是get_region_box。大概流程:
1、对每个候选框利用get_region_boxe函数计算bbox,这个bbox是归一化的。
2、求出类别概率最大的类别,然后乘以是否是物体的概率。
3、将计算出来的归一化bbox的尺度变换成与原始图片的尺度一样。
代码:
void get_region_boxes(layer l, int w, int h, int netw, int neth, float thresh, float **probs, box *boxes, int only_objectness, int *map, float tree_thresh, int relative)
{
int i,j,n,z;
float *predictions = l.output;
if (l.batch == 2) {
float *flip = l.output + l.outputs;
for (j = 0; j < l.h; ++j) {
for (i = 0; i < l.w/2; ++i) {
for (n = 0; n < l.n; ++n) {
for(z = 0; z < l.classes + 5; ++z){
int i1 = z*l.w*l.h*l.n + n*l.w*l.h + j*l.w + i;
int i2 = z*l.w*l.h*l.n + n*l.w*l.h + j*l.w + (l.w - i - 1);
float swap = flip[i1];
flip[i1] = flip[i2];
flip[i2] = swap;
if(z == 0){
flip[i1] = -flip[i1];
flip[i2] = -flip[i2];
}
}
}
}
}
for(i = 0; i < l.outputs; ++i){
l.output[i] = (l.output[i] + flip[i])/2.;
}
}
for (i = 0; i < l.w*l.h; ++i){
int row = i / l.w;
int col = i % l.w;
for(n = 0; n < l.n; ++n){
int index = n*l.w*l.h + i;
for(j = 0; j < l.classes; ++j){
probs[index][j] = 0;
}
int obj_index = entry_index(l, 0, n*l.w*l.h + i, 4);
int box_index = entry_index(l, 0, n*l.w*l.h + i, 0);
float scale = predictions[obj_index];//是否是物体的概率
boxes[index] = get_region_box(predictions, l.biases, n, box_index, col, row, l.w, l.h, l.w*l.h);//计算出归一化的bbox
int class_index = entry_index(l, 0, n*l.w*l.h + i, 5);
if(l.softmax_tree){//不考虑这个
hierarchy_predictions(predictions + class_index, l.classes, l.softmax_tree, 0, l.w*l.h);
if(map){
for(j = 0; j < 200; ++j){
int class_index = entry_index(l, 0, n*l.w*l.h + i, 5 + map[j]);
float prob = scale*predictions[class_index];
probs[index][j] = (prob > thresh) ? prob : 0;
}
} else {
int j = hierarchy_top_prediction(predictions + class_index, l.softmax_tree, tree_thresh, l.w*l.h);
probs[index][j] = (scale > thresh) ? scale : 0;
probs[index][l.classes] = scale;
}
} else {
float max = 0;
for(j = 0; j < l.classes; ++j){
int class_index = entry_index(l, 0, n*l.w*l.h + i, 5 + j);
float prob = scale*predictions[class_index];//类别概率乘以是否是物体的概率
probs[index][j] = (prob > thresh) ? prob : 0;
if(prob > max) max = prob;
// TODO REMOVE
// if (j == 56 ) probs[index][j] = 0;
/*
if (j != 0) probs[index][j] = 0;
int blacklist[] = {121, 497, 482, 504, 122, 518,481, 418, 542, 491, 914, 478, 120, 510,500};
int bb;
for (bb = 0; bb < sizeof(blacklist)/sizeof(int); ++bb){
if(index == blacklist[bb]) probs[index][j] = 0;
}
*/
}
probs[index][l.classes] = max;
}
if(only_objectness){
probs[index][0] = scale;
}
}
}
correct_region_boxes(boxes, l.w*l.h*l.n, w, h, netw, neth, relative);//将归一化bbox尺度映射到原始图片的尺度
}