首先,python接口darknet.py中detect函数如下:

def detect(net, meta, image, thresh=.5, hier_thresh=.5, nms=.45):im = load_image(image, 0, 0)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].bboxres.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

首先image传入后通过load_image()函数读取,load_image()函数导入见darknet.py中的lib,如下:

load_image = lib.load_image_color
load_image.argtypes = [c_char_p, c_int, c_int]
load_image.restype = IMAGE

具体通过编译好的libdarknet.so传入,首先市容load_image_color()函数,还函数位于src/image.c中,具体如下:

image load_image_color(char *filename, int w, int h)
{return load_image(filename, w, h, 3);
}

可以发现load_image_color()传入三个参数,除了image name外还有int w和int h,而在detect()中可以发现只传入了load_image(image, 0, 0),那么这个w=0和h=0该怎么算呢?继续往下看,发现调用了image.c中的load_image()函数,而该函数如下:

image load_image(char *filename, int w, int h, int c)
{
#ifdef OPENCVimage out = load_image_cv(filename, c);
#elseimage out = load_image_stb(filename, c);
#endifif((h && w) && (h != out.h || w != out.w)){image resized = resize_image(out, w, h);free_image(out);out = resized;}return out;
}

发现使用了opencv中的load_image_cv读取图像,而传入进来的h和w其实是在下面使用resize_image()操作对图片做了resize操作。至此发现darknet.py中的detect()使用的load_image(image, 0, 0)意思是只读入图片而不对其进行resize操作。那么load_image_cv读取到的图像返回三个值,即真实的image、image.w和image.h,这里即为out,然后返回至detect()中的im。紧接着,im传递给predict_image(net, im)函数进行预测,那么predic_image()我们下次再进行解读。那么真实的im.w和im.h(即图像的原始宽和高)被传递给dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, None, 0, pnum)函数,那么我们看一下此处的w和h到底起什么作用。get_network_boxes()函数在src/network.c中,函数如下:

detection *get_network_boxes(network *net, int w, int h, float thresh, float hier, int *map, int relative, int *num)
{detection *dets = make_network_boxes(net, thresh, num);fill_network_boxes(net, w, h, thresh, hier, map, relative, dets);return dets;
}

那么我们看到fill_network_boxes()使用了该函数,我们看明白了,在检测过程中并没有用到此处的w和h,那么这个原始图像的w和h干嘛用了呢?继续喊fill_network_boxes()函数,如下:

void fill_network_boxes(network *net, int w, int h, float thresh, float hier, int *map, int relative, detection *dets)
{int j;for(j = 0; j < net->n; ++j){layer l = net->layers[j];if(l.type == YOLO){ //yolov3int count = get_yolo_detections(l, w, h, net->w, net->h, thresh, map, relative, dets);dets += count;}if(l.type == REGION){  //yolov2get_region_detections(l, w, h, net->w, net->h, thresh, map, hier, relative, dets);dets += l.w*l.h*l.n;}if(l.type == DETECTION){  //yolov1get_detection_detections(l, w, h, thresh, dets);dets += l.w*l.h*l.n;}}
}

在yolov3中使用了get_yolo_detections()函数,并传入w和h,另外可以发现同时传入的还有net的w和h,net即是我们的yolov3网络,可以发现cfg中定义的w和h被一并传入至get_yolo_detections()中,继续看该函数(位于src/yolo_layer.c中):

int get_yolo_detections(layer l, int w, int h, int netw, int neth, float thresh, int *map, int relative, detection *dets)
{int i,j,n;float *predictions = l.output;if (l.batch == 2) avg_flipped_yolo(l);int count = 0;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 obj_index  = entry_index(l, 0, n*l.w*l.h + i, 4);float objectness = predictions[obj_index];if(objectness <= thresh) continue;int box_index  = entry_index(l, 0, n*l.w*l.h + i, 0);dets[count].bbox = get_yolo_box(predictions, l.biases, l.mask[n], box_index, col, row, l.w, l.h, netw, neth, l.w*l.h);dets[count].objectness = objectness;dets[count].classes = l.classes;for(j = 0; j < l.classes; ++j){int class_index = entry_index(l, 0, n*l.w*l.h + i, 4 + 1 + j);float prob = objectness*predictions[class_index];dets[count].prob[j] = (prob > thresh) ? prob : 0;}++count;}}correct_yolo_boxes(dets, count, w, h, netw, neth, relative);return count;
}

可以发现我们的原始图像传入的w和h只被correct_yolo_boxes()函数使用,correct是准确的意思,顾名思义,该函数得到准确的yolo检测框,详细看该函数:

void correct_yolo_boxes(detection *dets, int n, int w, int h, int netw, int neth, int relative)
{int i;int new_w=0;int new_h=0;if (((float)netw/w) < ((float)neth/h)) {new_w = netw;new_h = (h * netw)/w;} else {new_h = neth;new_w = (w * neth)/h;}for (i = 0; i < n; ++i){box b = dets[i].bbox;b.x =  (b.x - (netw - new_w)/2./netw) / ((float)new_w/netw); b.y =  (b.y - (neth - new_h)/2./neth) / ((float)new_h/neth); b.w *= (float)netw/new_w;b.h *= (float)neth/new_h;if(!relative){b.x *= w;b.w *= w;b.y *= h;b.h *= h;}dets[i].bbox = b;}
}

可以看出,最终原始图像的w和h的作用是和cfg传入的net-w和h一起经过计算将预测出的原始boxes映射回对应于原图的boxes坐标。即比如net中测试图像的resize大小为608x608,则预测的初始boxes的坐标对应的是608x608的,而原图比如为1920x1080的,那么就需要原图的w和h传入进行映射计算得到最终的boxes坐标。所以,检测时进行的image resize操作应当位于未讲解的predic_image()函数中。

darknet-yolov3中python接口中image传输w和h的过程相关推荐

  1. darknet 框架中.cfg文件的参数详解,以yolov3为例

    参考:darknet中cfg文件里参数的理解_zerojava0的博客-CSDN博客 参考:[Darknet源码 ]cfg文件参数详解_橘子都吃不起!的博客-CSDN博客 1.基础参数解释 batch ...

  2. YOLOV3中Darknet中cfg文件说明和理解

    darknet 是由 C 和 CUDA 开发的,不需要配置其他深度学习的框架(如,tensorflow.caffe 等),支持 CPU 和 GPU 运算,而且安装过程非常简单. 1.cfg文件说明理解 ...

  3. AlexeyAB DarkNet YOLOv3框架解析与应用实践(二)

    AlexeyAB DarkNet YOLOv3框架解析与应用实践(二) 版本3有什么新功能? YOLOv3使用了一些技巧来改进训练和提高性能,包括:多尺度预测.更好的主干分类器等等.全部细节都在我们的 ...

  4. alexeyab darknet 编译_【目标检测实战】Darknet—yolov3模型训练(VOC数据集)

    原文发表在:语雀文档 0.前言 本文为Darknet框架下,利用官方VOC数据集的yolov3模型训练,训练环境为:Ubuntu18.04下的GPU训练,cuda版本10.0:cudnn版本7.6.5 ...

  5. 小白教程:Ubuntu下使用Darknet/YOLOV3训练自己的数据集

    小白教程:Ubuntu下使用Darknet/YOLOV3训练自己的数据集 YOLOV3官网教程:https://pjreddie.com/darknet/yolo/ 使用预训练模型进行检测 git c ...

  6. AlexeyAB DarkNet YOLOv3框架解析与应用实践(六)

    AlexeyAB DarkNet YOLOv3框架解析与应用实践(六) Tiny Darknet 听过很多人谈论SqueezeNet. SqueezeNet很酷,但它只是优化参数计数.当大多数高质量的 ...

  7. AlexeyAB DarkNet YOLOv3框架解析与应用实践(五)

    AlexeyAB DarkNet YOLOv3框架解析与应用实践(五) RNNs in Darknet 递归神经网络是表示随时间变化的数据的强大模型.为了更好地介绍RNNs,我强烈推荐Andrej K ...

  8. AlexeyAB DarkNet YOLOv3框架解析与应用实践(四)

    AlexeyAB DarkNet YOLOv3框架解析与应用实践(四) Nightmare 从前,在一所大学的大楼里,西蒙尼亚.维达第和齐瑟曼有一个很好的主意,几乎和你现在坐的大楼完全不同.他们想,嘿 ...

  9. AlexeyAB DarkNet YOLOv3框架解析与应用实践(三)

    AlexeyAB DarkNet YOLOv3框架解析与应用实践(三) ImageNet分类 您可以使用Darknet为1000级ImageNet挑战赛分类图像.如果你还没有安装Darknet,你应该 ...

最新文章

  1. oracle 无备份恢复数据文件
  2. oracle biee
  3. centos7 mysql 5.5.27_centos7上安装mysql-5.7.27
  4. chrome inspect 远程调测:Chrome on Android之一 普通调试
  5. SyncBird Pro的PhoneCare功能如何使用
  6. mediaplay抓图
  7. TTC - Building a Better Vocabulary
  8. Linux完全卸载mysql数据库
  9. C语言自学——lesson4
  10. 波特率和比特率之间的关系
  11. 1.用 perf report 分析四个for进程
  12. 20200415 计算机的基础之host配置
  13. 苏宁易购为京东量身打造北京攻略
  14. Graph Representation Learning via Graphical Mutual Information Maximization
  15. 苹果手机没有备份怎么恢复照片?
  16. Java程序入门教程 | Java
  17. Python环境配置与数据处理
  18. 人工智能数学基础--导数3:隐函数求导、对数求导法、参数方程求导法
  19. js-day01-02
  20. 代码模块化和可读性的tradeoff

热门文章

  1. 使用python tkinter做window窗体界面程序,以及python多线程处理解决tk界面卡死
  2. 如何利用最少的钱,快速打开淘宝流量入口?
  3. mac安装chromedriver驱动详细步骤
  4. Java调用海康威视接口并抓取Jpeg图片到内存
  5. 光伏产业的机会 -- 光伏储能并网
  6. MIMO-OFDM无线通信技术及MATLAB实现PDF及其代码
  7. Vue和Vue-Element-Admin(七):把管理系统发布阿里云(公网)
  8. 2023,我们要走的路还有很长~
  9. 今天向大家介绍一个快应用开发辅助IDE插件——Troll For Ux
  10. 微信小程序调用腾讯地图,获取当前位置得到数据有偏差以及不同软件,不同坐标之间的转换Gcoord