yolov3前向传播(三)-- 坐标转换,iou计算,权重加载,图片显示
坐标转换,iou计算,权重加载,图片显示
一、坐标转换
1、分析
2、实现
# =====================================坐标值转化函数==========================================================
# 定义函数:将中心点、高、宽坐标 转化为[x0, y0, x1, y1]坐标形式
# 将anchor的中心点坐标表示形式转化为左上右下坐标表示形式
def detections_boxes(detections):''':param detections: YOLO检测层的输出 形状 (1, 10647, 5+num_anchor):return:将anchor的中心点坐标表示形式转化为左上右下坐标表示形式的所有anchor 形状 (1, 10647, 5+num_anchor)'''# 将detections (1, 10647, 5+num_class) 切分为(1, 10647, 1)、(1, 10647, 1)、(1, 10647, 1)、(1, 10647, 1)、(1, 10647, num_class+1)center_x, center_y, width, height, attrs = tf.split(detections, [1, 1, 1, 1, -1], axis=-1)w2 = width / 2 # 二分之1宽h2 = height / 2 # 二分之1高x0 = center_x - w2 # anchor左上角 x 值y0 = center_y - h2 # anchor左上角 y 值x1 = center_x + w2 # anchor右下角 x 值y1 = center_y + h2 # anchor右下角 y 值# 将坐标值放到一起 一列是一个anchor的左上右下坐标值boxes = tf.concat([x0, y0, x1, y1], axis=-1)# 再组合回去 detections 形状 (1, 10647, 5+num_anchor)detections = tf.concat([boxes, attrs], axis=-1)return detections
二、IOU计算函数
1、分析
2、实现
# =====================================IOU计算函数==========================================================
#定义函数计算两个框的内部重叠情况(IOU)box1,box2为左上、右下的坐标[x0, y0, x1, x2]
# 计算两个anchor的IOU值
def _iou(box1, box2):''':param box1: 第一个anchor的左上右下坐标,形如[x0, y0, x1, y1]:param box2: 第二个anchor的左上右下坐标,形如[x0, y0, x1, y1]:return: 两个anchor的IOU值'''# 获取具体坐标值b1_x0, b1_y0, b1_x1, b1_y1 = box1b2_x0, b2_y0, b2_x1, b2_y1 = box2# 计算两个anchor重叠部分的坐标# 前两行的较大的值的组合是属于两个anchor重叠部分的右上角的坐标# 后两行的较小的值的组合是属于两个anchor重叠部分的左下角的坐标int_x0 = max(b1_x0, b2_x0)int_y0 = max(b1_y0, b2_y0)int_x1 = min(b1_x1, b2_x1)int_y1 = min(b1_y1, b2_y1)# 计算anchor重叠的面积int_area = (int_x1 - int_x0) * (int_y1 - int_y0)# 分别计算两个anchor的面积b1_area = (b1_x1 - b1_x0) * (b1_y1 - b1_y0)b2_area = (b2_x1 - b2_x0) * (b2_y1 - b2_y0)# 计算两个anchor的IOU值,两个anchor的交集面积除以两个anchor并集的面积#分母加个1e-05,避免除数为 0iou = int_area / (b1_area + b2_area - int_area + 1e-05)return iou
三、非极大值抑制函数
1、分析
2、实现
# ====================================================== 使用非极大值抑制(NMS)方法,对结果去重===================================================
def non_max_suppression(predictions_with_boxes, confidence_threshold, iou_threshold=0.4):''':param predictions_with_boxes: YOLO检测层的输出经过detections_boxes处理之后。 形如 [1, 10647, 5+num_anchor]:param confidence_threshold: 置信度阈值:param iou_threshold: iou阈值:return:同一类别中,相距比较远的anchor。'''# predictions_with_boxes[:, :, 4] 是获取到predictions_with_boxes中的confidence值,形状类似为 [1,10647]# predictions_with_boxes[:, :, 4] > confidence_threshold 判断所有anchor的confidence值是否大于confidence_threshold,返回true或者false 形状类似为 [1,10647]# np.expand_dims((predictions_with_boxes[:, :, 4] > confidence_threshold), -1) 将形状[1,10647] 在最后一个维度增加一个维度 形状变成[1,10647,1]# conf_mask = [[[False],[ True],...,[ True]]] 形状[1,10647,1]conf_mask = np.expand_dims((predictions_with_boxes[:, :, 4] > confidence_threshold), -1)# 利用conf_mask值将predictions_with_boxes中小于confidence_threshold的值的confidence变成0(实际上一行数据全变成0了) 原理 True*数值 = 原数值 False*数值 = 0# 满足置信度条件的anchor的预测值不变,不满足置信度条件的anchor的预测值全变成0# predictions_with_boxes的形状为[1,10647,5+c]# predictions 的形状为[1,10647,5+c] 只是不满足置信度条件的anchor的预测值全变成0predictions = predictions_with_boxes * conf_mask # 矩阵对应值相乘result = {} # 定义键值对备用for i, image_pred in enumerate(predictions): # 遍历置信度处理后的prediction 形状为 [1,10647,5+c] 其中5是左上坐标x0 y0 右下坐标x1 y1 置信度confidence c是分类数shape = image_pred.shape # 获取prediction中每一个元素的形状print("shape1",shape) # 形状[10647,5+c]non_zero_idxs = np.nonzero(image_pred) # 返回非0元素下标 这是所有维度的组合坐标 我们只需要第一个维度非0值的坐标unique_idxs = list(set(non_zero_idxs[0])) # 得到第一个维度非0值的坐标image_pred = image_pred[unique_idxs] # 获取非0元素下标的预测值 形状[满足置信度条件的anchor个数,5+c]print("shape2",image_pred.shape) # 形状[满足置信度条件的anchor个数,5+c]image_pred = image_pred.reshape(-1, shape[-1]) # 形状[满足置信度条件的anchor个数,5+c]bbox_attrs = image_pred[:, :5] # 满足置信度条件的预测值的前5个预测值:位置和置信度预测值 形状[满足置信度条件的anchor个数,5]classes = image_pred[:, 5:] # 满足置信度条件的预测值的前5个以后预测值:分类预测值 形状[满足置信度条件的anchor个数,c]classes = np.argmax(classes, axis=-1) # 获取满足置信度条件的分类预测值的预测编号 形状[满足置信度条件的anchor个数,] 1维unique_classes = list(set(classes.reshape(-1))) # 去重 获得该图片中的分类种类 形状[该图片中的分类种类数,]1维for cls in unique_classes: # 遍历该图片中的每一种类别# 判断classes中每个元素是否等于cls,元素等于是True不等是Falsecls_mask = classes == cls # 判断class中属于当前分类 cls类有哪些元素,True代表属于,False代表不属于 返回cls_mask 内容类似于[False True False ... True False]# np.nonzero(cls_mask) 返回cls_mask中的非0的元素的下标# 根据下标找到同一类的所有anchor。形状[满足置信度条件的属于同一类别的anchor个数,5] 5 左上右下坐标+置信度cls_boxes = bbox_attrs[np.nonzero(cls_mask)] # cls_boxes形状[满足置信度条件的属于同一类别的anchor个数,5]cls_boxes = cls_boxes[cls_boxes[:, -1].argsort()[::-1]] # 将同一类别的anchor按照置信度的大小排序。由大到小 形状[满足置信度条件的属于同一类别的anchor个数,5]cls_scores = cls_boxes[:, -1] # 获取同一类别的anchor的置信度[满足置信度条件的属于同一类别的anchor个数,1] 同一类anchor置信度排序后的置信度cls_boxes = cls_boxes[:, :-1] # 获取同一类别的anchor的置信度[满足置信度条件的属于同一类别的anchor个数,4]同一类anchor置信度排序后的anchor左上右下坐标while len(cls_boxes) > 0: # 终止条件cls_boxes中没有元素了box = cls_boxes[0] # 由于cls_boxes存放的是同一类anchor置信度排序后的anchor左上右下坐标,所以cls_boxes[0]代表的是置信度最大的anchorscore = cls_scores[0] # 获取最大置信度anchor的置信度值if not cls in result: # 如果该分类不在键值对result中,则生成以该分类为键,以列表为值的键值对result[cls] = []result[cls].append((box, score)) # 将最大置信度anchor的坐标值,和置信度值添加到以该分类为键,以列表为值的列表中cls_boxes = cls_boxes[1:] # 用列表存放除了最大置信度anchor之外的所有anchorious = np.array([_iou(box, x) for x in cls_boxes]) # 由最大置信度anchor依次与除了最大置信度anchor之外的所有anchor一个个的做IOU计算,计算结果存放到ious中,计算顺序是按照置信度大小的顺序iou_mask = ious < iou_threshold # 找到上一步计算的iou值列表中那些元素小于IOU阈值cls_boxes = cls_boxes[np.nonzero(iou_mask)] # 找到iou列表中小于等于iou阈值的所有元素的下标,并根据下标找到对应的anchor,其顺序依然是按照置信度大小由大到小排列的cls_scores = cls_scores[np.nonzero(iou_mask)] # 找到iou列表中小于等于iou阈值的所有元素的下标,并根据下标找到对应的anchor,其顺序依然是按照置信度大小由大到小排列的# 接着找最大最大置信度anchor,与余下的anchor接着做iou计算重复while的内容,最终保留同一类别中,相距比较远的anchor。return result
四、结果显示
即将检测结果显示在图片上
1、分析
2、实现
# 将检测结果显示在图片上
def draw_boxes(boxes, img, cls_names, detection_size):''':param boxes: 非极大值抑制后的anchor框 形如{0: [(array([16., 30., 35., 45.]), 0.5)], 2: [(array([ 5., 8., 15., 14.]), 0.7)], 3: [(array([43., 53., 65., 65.]), 0.6), (array([15., 18., 25., 24.]), 0.6)], 4: [(array([27., 25., 37., 28.]), 0.5)]}:param img: 输入到网络的原图片:param cls_names: 分类编号和分类名称对应的字典:param detection_size: 输入到网络的原图片统一调整后的大小 这里是416:return: 在原图上画好框标好分类的原图片'''draw = ImageDraw.Draw(img) # 创建一个可以在给定图像(img)上绘图的对象for cls, bboxs in boxes.items(): # 遍历键值对的键和值 键cls表示分类 值bboxs表示坐标+置信度 形状[2],即[(4个坐标值),(1个置信度)]color = tuple(np.random.randint(0, 256, 3)) # 产生代表随机颜色随机数for box, score in bboxs: # 遍历坐标和置信度box = convert_to_original_size(box, np.array(detection_size), np.array(img.size)) # 从416*416大小图片上还原到原始图片大小draw.rectangle(box, outline=color) # 依据坐标点和随机颜色画出相应的anchordraw.text(box[:2], '{} {:.2f}%'.format(cls_names[cls], score * 100), fill=color) # 在框的左上角写上分类名称和置信度print('{} {:.2f}%'.format(cls_names[cls], score * 100),box[:2])def convert_to_original_size(box, size, original_size): # 从416*416大小图片上还原到原始图片大小''':param box: 基于416*416图片上的anchor坐标 形如[16., 30., 35., 45.] 左上右下坐标:param size: 预测时所有图片统一后的大小 这里是416:param original_size: 没有统一大小时的原图片的大小:return: 返回基于416*416图片上的anchor坐标还原到没有统一大小时的原图片的大小上的坐标,即等比例缩放'''ratio = original_size / size # 缩放比例box = box.reshape(2, 2) * ratio # 根据缩放比例进行缩放坐标return list(box.reshape(-1)) # 将缩放后的坐标变成 一行数据 即维度为1的列表
五、权重加载
1、实现
def load_weights(var_list, weights_file):''':param var_list: 变量名称列表:param weights_file: 二进制基于coco训练的基于darknet53的yolov3权重:return: 权重op'''# 以读二进制的方式打开文件# np.fromfile(frame, dtype=float, count=‐1, sep='')# frame : 文件、字符串# dtype : 读取的数据类型# count : 读入元素个数,‐1表示读入整个文件 5表示读取前5个int32# sep : 数据分割字符串,如果是空串,写入文件为二进制with open(weights_file, "rb") as fp:# 读取前5个int32,不要,前5个int32是标题信息_ = np.fromfile(fp, dtype=np.int32, count=5) # 跳过前5个int32# 接着读取最后的所有float32,存入weights列表中weights = np.fromfile(fp, dtype=np.float32)ptr = 0i = 0 # 计数变量assign_ops = []while i < len(var_list) - 1: # 遍历变量列表var1 = var_list[i] # 从变量列表中获取第一个变量var2 = var_list[i + 1] # 从变量列表中获取第二个变量# 到卷积项if 'Conv' in var1.name.split('/')[-2]: # 按'/'分割var1.name,然后返回倒数第二个元素,并判断'Conv'是否在返回的元素中# 找到BN参数项if 'BatchNorm' in var2.name.split('/')[-2]:# 按'/'分割var1.name,然后返回倒数第二个元素,并判断'BatchNorm'是否在返回的元素中# 加载批量归一化参数gamma, beta, mean, var = var_list[i + 1:i + 5] # 从变量列表中获取BN参数batch_norm_vars = [beta, gamma, mean, var] # 将BN参数放到一个列表中for var in batch_norm_vars:shape = var.shape.as_list()num_params = np.prod(shape)var_weights = weights[ptr:ptr + num_params].reshape(shape)ptr += num_paramsassign_ops.append(tf.assign(var, var_weights, validate_shape=True))i += 4#已经加载了4个变量,指针移动4elif 'Conv' in var2.name.split('/')[-2]:bias = var2bias_shape = bias.shape.as_list()bias_params = np.prod(bias_shape)bias_weights = weights[ptr:ptr + bias_params].reshape(bias_shape)ptr += bias_paramsassign_ops.append(tf.assign(bias, bias_weights, validate_shape=True))i += 1#移动指针shape = var1.shape.as_list()num_params = np.prod(shape)#加载权重var_weights = weights[ptr:ptr + num_params].reshape((shape[3], shape[2], shape[0], shape[1]))var_weights = np.transpose(var_weights, (2, 3, 1, 0))ptr += num_paramsassign_ops.append(tf.assign(var1, var_weights, validate_shape=True))i += 1return assign_ops
yolov3前向传播(三)-- 坐标转换,iou计算,权重加载,图片显示相关推荐
- 学以致用三十四-----python2.0加载图片
想用做一个静态图片为背景的页面.结果遇到了一些阻碍.其主要原因还是路径没有找对.网上也参考了不少方法,也许是因为版本不同,处理的方法也不同,因此按照网上的处理方式,也没有得到解决. 为此困惑了一天.结 ...
- 前后端传图片用base64好吗_Base64是什么?前端用Base64加载图片到底好不好?
相信无论是前端还是后端开发工程师,对于Base64都不会感到陌生,在开发中我们经常会将一些小图片以Base64的形式存储和加载.然而知其然也要知其所以然,Base64究竟是什么,我们为什么要使用Bas ...
- Android简易实战教程--第三十二话《使用Lrucache和NetworkImageView加载图片》
转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/5279131 ...
- android开发学习之路——连连看之加载图片(三)
正如前面AbstractBoard类的代码中看到的,当程序需要创建N个Piece对象时,程序会直接调用ImageUtil的getPlayImages()方法去获取图片,该方法将会随机从res\ dra ...
- 【C++的OpenCV】第三课-OpenCV图像加载和显示
我们开始学习OpenCV 一.OpenCV加载图片和显示图片 1.1 imread()函数的介绍 1.2 cv::namedWindow()函数的介绍 1.4 imshow()函数介绍 1.5 Mat ...
- yolov3前向传播(二)-- yolov3相关模块的解析与实现(一)
yolov3检测块的解析与实现 在yolo v3模型中,检测部分的模型是由yolo检测块.yolo检测层以及上采样函数组成. yolo检测块负责进一步提取特征: 检测层负责将最终特征转化为bbox a ...
- yolov3前向传播(二)-- yolov3相关模块的解析与实现(二)
yolov3相关模块的解析与实现(二) 接上一篇 三.上采样函数 作用:用于将特征图扩展到想要的尺寸大小,和其他特征叠加到一起使用. 上采样的方法为近邻差值法 上采样函数的实现 # 定义上采样函数 d ...
- ignite mysql_apache ignite系列(三):数据处理(数据加载,数据并置,数据查询)
使用ignite的一个常见思路就是将现有的关系型数据库中的数据导入到ignite中,然后直接使用ignite中的数据,相当于将ignite作为一个缓存服务,当然ignite的功能远不止于此,下面以将 ...
- 页面加载图片前用空态图代替真正图片
这里简单说一下,用空太图来代替原始的图片.一般情况了,在图片加载前有 好几种方式: 比如: 1-图片懒加载, 2-图片预加载, 3-背景图代替, 4-空态图代替. 这里讲解一下空态图的方式: **CS ...
最新文章
- 全面访问JavaScript的最佳资源
- 以太网交换机与路由—Vecloud微云
- Codeforces Round #351 (VK Cup 2016 Round 3, Div. 2 Edition) A. Bear and Game 水题
- 对linux内核学习的一点感受,对linux内核学习的一点感受
- photoshop图像滤镜——素描算法(含matlab与C代码)
- php mysql书城_php在线书城 thinkphp源码(含数据库脚本)
- Notepad++中用正则表达式匹配中文
- 微软更新服务器win7,[技巧]绕过微软限制:让基于新处理器的Win7/8.1系统继续接收更新...
- 重构:改善既有代码的设计(评注版) 评注者序
- 2011年度最佳代码“不管你们信不信,我反正信了”
- 树:二叉树的内存拷贝和内存释放
- 基于JAVA+Servlet+JSP+MYSQL的人力资源管理系统
- python处理excel表格-Python利用pandas处理Excel数据的应用
- oracle11g 卸载步骤
- 认真与随便,结果有天壤之别
- 190815每日一句
- C# Winform 自动更新程序实例
- 永恒之蓝--Windows server 2003R2
- 百度地图API获取公交路线及站点数据
- phpStrom连接MySQL数据库