当前位置:网站首页>boundary IoU 的计算方式
boundary IoU 的计算方式
2022-07-05 22:03:00 【氵文大师】
Boundary IoU
说白了就是计算 预测图片的边界 和 GT图片的边界 的 IoU
就是酱紫的两个边界计算 IoU 就好
问题是怎么计算上图这样的边界呢? ,用Canny边缘检测之类的? 算个梯度? 可是要边界啊,在分割的区域内部也有可能有边缘啊,这个不是边界吧
我们可以采用Boundary IoU原文的计算方式
这是原图:
我们可以让原图缩小一圈,就像这样
然后原图减去缩小版的图,就得到了边界
那怎么才能得到缩小版的原图呢? 这就请出了主角:腐蚀
可以参考这里:
OpenCV 图像处理之膨胀与腐蚀
腐蚀操作和膨胀操作相反,也就是将毛刺消除,判断方法为:在卷积核大小中对图片进行卷积。
取图像中(3 * 3)区域内的最小值。由于我们是二值图像,也就是取0(黑色)。 总结: 只要原图片3 * 3范围内有黑的,该像素点就是黑的。
接下来直接看看代码吧,代码见 Reference:
# GitHub repo: https://github.com/bowenc0221/boundary-iou-api
# Reference: https://gist.github.com/bowenc0221/71f7a02afee92646ca05efeeb14d687d
import cv2
import numpy as np
import matplotlib.pyplot as plt
# General util function to get the boundary of a binary mask.
# 该函数用于获取二进制 mask 的边界
def mask_to_boundary(mask, dilation_ratio=0.02):
""" Convert binary mask to boundary mask. :param mask (numpy array, uint8): binary mask :param dilation_ratio (float): ratio to calculate dilation = dilation_ratio * image_diagonal :return: boundary mask (numpy array) """
h, w = mask.shape
img_diag = np.sqrt(h ** 2 + w ** 2) # 计算图像对角线长度
dilation = int(round(dilation_ratio * img_diag))
if dilation < 1:
dilation = 1
# Pad image so mask truncated by the image border is also considered as boundary.
new_mask = cv2.copyMakeBorder(mask, 1, 1, 1, 1, cv2.BORDER_CONSTANT, value=0)
kernel = np.ones((3, 3), dtype=np.uint8)
new_mask_erode = cv2.erode(new_mask, kernel, iterations=dilation)
# 因为之前向四周填充了0, 故而这里不再需要四周
mask_erode = new_mask_erode[1 : h + 1, 1 : w + 1]
# G_d intersects G in the paper.
return mask - mask_erode
def boundary_iou(gt, dt, dilation_ratio=0.02):
""" Compute boundary iou between two binary masks. :param gt (numpy array, uint8): binary mask :param dt (numpy array, uint8): binary mask :param dilation_ratio (float): ratio to calculate dilation = dilation_ratio * image_diagonal :return: boundary iou (float) """
gt_boundary = mask_to_boundary(gt, dilation_ratio)
dt_boundary = mask_to_boundary(dt, dilation_ratio)
intersection = ((gt_boundary * dt_boundary) > 0).sum()
union = ((gt_boundary + dt_boundary) > 0).sum()
boundary_iou = intersection / union
return boundary_iou
mask_to_boundary
函数用于计算边界的 mask,而 boundary_iou
用于计算 boundary_iou
,boundary_iou
中会调用 mask_to_boundary
.
这一行用于给原图的四周添加0, 这样连边界区域的目标像素也会被腐蚀掉
# Pad image so mask truncated by the image border is also considered as boundary.
new_mask = cv2.copyMakeBorder(mask, 1, 1, 1, 1, cv2.BORDER_CONSTANT, value=0)
以下是 cv2.copyMakeBorder
操作的示意图,其实直接叫 Padding 就好了
这两行用于给图像做腐蚀操作,kernel size 是(3, 3)
kernel = np.ones((3, 3), dtype=np.uint8)
new_mask_erode = cv2.erode(new_mask, kernel, iterations=dilation) # iterations 指的是腐蚀的次数
再来看下 dilation 的计算:
h, w = mask.shape
img_diag = np.sqrt(h ** 2 + w ** 2) # 计算图像对角线长度
dilation = int(round(dilation_ratio * img_diag))
if dilation < 1:
dilation = 1
腐蚀的次数与对角线的长度成正比,如果小于1则直接给1,dilation_ratio
是函数的参数
再看最后一步:
# 因为之前向四周填充了0, 故而这里不再需要四周
mask_erode = new_mask_erode[1 : h + 1, 1 : w + 1]
将周边的padding像素去掉,之后再将二者减掉就可:
return mask - mask_erode
最后就得到这个图:
boundary_iou
的计算方式和一般的 IoU 计算方式一样,有个问题就是,如果交集onion==0
时,可能存在除0错误的问题,他这个代码里没有
所以应该改为:
def boundary_iou(gt, dt, dilation_ratio=0.02):
""" Compute boundary iou between two binary masks. :param gt (numpy array, uint8): binary mask :param dt (numpy array, uint8): binary mask :param dilation_ratio (float): ratio to calculate dilation = dilation_ratio * image_diagonal :return: boundary iou (float) """
gt_boundary = mask_to_boundary(gt, dilation_ratio)
dt_boundary = mask_to_boundary(dt, dilation_ratio)
intersection = ((gt_boundary * dt_boundary) > 0).sum()
union = ((gt_boundary + dt_boundary) > 0).sum()
if union < 1:
return 0
boundary_iou = intersection / union
return boundary_iou
边栏推荐
- 华为游戏多媒体调用切换房间方法出现异常Internal system error. Reason:90000017
- Summarize the reasons for 2XX, 3xx, 4xx, 5xx status codes
- poj 3237 Tree(树链拆分)
- 总结出现2xx、3xx、4xx、5xx状态码的原因
- 1.3 years of work experience, double non naked resignation agency face-to-face experience [already employed]
- 让开发效率提升的跨端方案
- regular expression
- crm创建基于fetch自己的自定义报告
- Implementing Lmax disruptor queue from scratch (IV) principle analysis of multithreaded producer multiproducersequencer
- 大约SQL现场“这包括”与“包括在”字符串的写法
猜你喜欢
Web3为互联网带来了哪些改变?
Advantages and disadvantages of the "Chris Richardson microservice series" microservice architecture
Interprocess communication in the "Chris Richardson microservice series" microservice architecture
The American Championship is about to start. Are you ready?
Performance monitoring of database tuning solutions
matlab绘制hsv色轮图
Win11缺少dll文件怎么办?Win11系统找不到dll文件修复方法
Learning of mall permission module
元宇宙中的三大“派系”
Deeply convinced plan X - network protocol basic DNS
随机推荐
华为云ModelArts文本分类–外卖评论
Common interview questions of redis factory
Robot framework setting variables
Detailed explanation of memset() function usage
How to develop and introduce applet plug-ins
微服务链路风险分析
HDU 4391 paint the wall segment tree (water
微服务入门(RestTemplate、Eureka、Nacos、Feign、Gateway)
[Yugong series] go teaching course in July 2022 004 go code Notes
Interview questions for basic software testing
matlab绘制hsv色轮图
Poj 3237 Tree (Tree Chain Split)
Oracle checkpoint queue - Analysis of the principle of instance crash recovery
【愚公系列】2022年7月 Go教学课程 003-IDE的安装和基本使用
Oracle检查点队列–实例崩溃恢复原理剖析
CRM creates its own custom report based on fetch
华为快游戏调用登录接口失败,返回错误码 -1
Blocking protocol for concurrency control
Pointer parameter passing vs reference parameter passing vs value parameter passing
EBS Oracle 11g cloning steps (single node)