图像匹配 | NCC 归一化互相关损失 | 代码 + 讲解
- 文章转载自:微信公众号「机器学习炼丹术」
- 作者:炼丹兄(已授权)
- 作者联系方式:微信cyx645016617(欢迎交流共同进步)
本次的内容主要讲解NCCNormalized cross-correlation 归一化互相关。
两张图片是否是同一个内容,现在深度学习的方案自然是用神经网络,比方说:孪生网络的架构做人面识别等等;
在传统的非参数方法中,常见的也有相关系数等。我在上一片文章voxelmorph的模型的学习中发现,在医学图像配准任务(不限于医学),衡量两个图片相似的度量有一种叫做NCC的
而这个NCC就是Normalized Cross-Correlation归一化互相关系数。
1 互相关系数
如果你知道互相关系数,那么你就能很好的理解归一化互相关系数。
相关系数的计算公式如下:
\]
公式中的X,Y分别表示两个图片,\(Cov(X,Y)\)表示两个图片的协方差,\(Var(X)\)表示X自身的方差;
2 归一化互相关NCC
如果把一张图片,按照一定的像素,比方说9x9的一个框滑动,那么就可以把图片分成很多的9x9的小图片,那么NCC就是X,Y两张大图片中的对应的小图片的互相关系数的平均值。
这里看一下协方差的计算方式:
\(Cov(X,Y) = E[(X-E(X))(Y-E(Y))]\)
方差的计算为:
\(Var(X) = E[(X-E(X))^2]\)
其实NCC不难理解,但是如何用代码计算呢?当然我们可以一行一行遍历求解,但是这样时间复杂度过高,所以我们做好还是选择矩阵运算。
3 NCC损失函数的代码
class NCC:
"""
Local (over window) normalized cross correlation loss.
"""
def __init__(self, win=None):
self.win = win
def loss(self, y_true, y_pred):
I = y_true
J = y_pred
# get dimension of volume
# assumes I, J are sized [batch_size, *vol_shape, nb_feats]
ndims = len(list(I.size())) - 2
assert ndims in [1, 2, 3], "volumes should be 1 to 3 dimensions. found: %d" % ndims
# set window size
win = [9] * ndims if self.win is None else self.win
# compute filters
sum_filt = torch.ones([1, 1, *win]).to("cuda")
pad_no = math.floor(win[0]/2)
if ndims == 1:
stride = (1)
padding = (pad_no)
elif ndims == 2:
stride = (1,1)
padding = (pad_no, pad_no)
else:
stride = (1,1,1)
padding = (pad_no, pad_no, pad_no)
# get convolution function
conv_fn = getattr(F, 'conv%dd' % ndims)
# compute CC squares
I2 = I * I
J2 = J * J
IJ = I * J
I_sum = conv_fn(I, sum_filt, stride=stride, padding=padding)
J_sum = conv_fn(J, sum_filt, stride=stride, padding=padding)
I2_sum = conv_fn(I2, sum_filt, stride=stride, padding=padding)
J2_sum = conv_fn(J2, sum_filt, stride=stride, padding=padding)
IJ_sum = conv_fn(IJ, sum_filt, stride=stride, padding=padding)
win_size = np.prod(win)
u_I = I_sum / win_size
u_J = J_sum / win_size
cross = IJ_sum - u_J * I_sum - u_I * J_sum + u_I * u_J * win_size
I_var = I2_sum - 2 * u_I * I_sum + u_I * u_I * win_size
J_var = J2_sum - 2 * u_J * J_sum + u_J * u_J * win_size
cc = cross * cross / (I_var * J_var + 1e-5)
return -torch.mean(cc)
这段代码其实不是很好看懂,我思考了很久才明白。其中的关键就在于如何理解:
# compute CC squares
I2 = I * I
J2 = J * J
IJ = I * J
I_sum = conv_fn(I, sum_filt, stride=stride, padding=padding)
J_sum = conv_fn(J, sum_filt, stride=stride, padding=padding)
I2_sum = conv_fn(I2, sum_filt, stride=stride, padding=padding)
J2_sum = conv_fn(J2, sum_filt, stride=stride, padding=padding)
IJ_sum = conv_fn(IJ, sum_filt, stride=stride, padding=padding)
win_size = np.prod(win)
u_I = I_sum / win_size
u_J = J_sum / win_size
cross = IJ_sum - u_J * I_sum - u_I * J_sum + u_I * u_J * win_size
I_var = I2_sum - 2 * u_I * I_sum + u_I * u_I * win_size
J_var = J2_sum - 2 * u_J * J_sum + u_J * u_J * win_size
我们可以才到,这个cross应该是协方差部分,I_var和J_var是方差部分。
我们对协方差公式进行推导:\(Cov(X,Y) = E[(X-E(X))(Y-E(Y))]\)
\(=E[XY-XE(Y)-YE(X)+E(X)E(Y)]\)
这样刚好和cross对应上。
- IJ_sum = E[XY]
- u_J * I_sum = E[XE(Y)]
- u_I * u_J * win_size = E[E(X)E(Y)]
对方差公式进行推导:\(Var(X) = E[(X-E(X))^2]=E[X^2-2XE(X)+E(X)^2]\)
- J2_sum = E(X^2)
- 2 * u_J * J_sum = E[2XE(X)]
- u_J * u_J * win_size = E[E(X)^2]
图像匹配 | NCC 归一化互相关损失 | 代码 + 讲解的更多相关文章
- 第二章--Win32程序运行原理 (部分概念及代码讲解)
学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...
- 『HTML5实现人工智能』小游戏《井字棋》发布,据说IQ上200才能赢【算法&代码讲解+资源打包下载】
一,什么是TicTacToe(井字棋) 本游戏为在下用lufylegend开发的第二款小游戏.此游戏是大家想必大家小时候都玩过,因为玩它很简单,只需要一张草稿纸和一只笔就能开始游戏,所以广受儿童欢迎. ...
- Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解
Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解 说明:Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解,实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返 ...
- faster RCNN(keras版本)代码讲解(3)-训练流程详情
转载:https://blog.csdn.net/u011311291/article/details/81121519 https://blog.csdn.net/qq_34564612/artic ...
- 毕业设计java实验室预约管理系统SSH机房预约系统javaweb机房实验室排课系统mysql机房管理系统 实验室管理系统 课程设计 代码讲解 调试运行
毕业设计java实验室预约管理系统SSH机房预约系统javaweb机房实验室排课系统mysql机房管理系统 实验室管理系统 课程设计 代码讲解 调试运行 注意:该项目只展示部分功能,如需了解,评论区咨 ...
- 双目立体匹配——归一化互相关(NCC)
归一化相关性,normalization cross-correlation,因此简称NCC,下文中笔者将用NCC来代替这冗长的名称. NCC,顾名思义,就是用于归一化待匹配目标之间的相关程度,注意这 ...
- CUDA学习,第一个kernel函数及代码讲解
前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...
- 李宏毅 Gradient Descent Demo 代码讲解
何为梯度下降,直白点就是,链式求导法则,不断更新变量值. 这里讲解的代码为李宏毅老师机器学习课程中 class 4 回归展示 中的代码demo Loss函数 python代码如下 import n ...
- Widget代码讲解
参考:https://zhuanlan.zhihu.com/p/28225011 QT版本为5.12.4 1.main.cpp #include "widget.h" #inclu ...
随机推荐
- codevs1169传纸条 不相交路径取最大,四维转三维DP
这个题一个耿直的思路肯定是先模拟.. 但是我们马上发现这是具有后效性的..也就是一个从(1,1)开始走,一个从(n,m)开始走的话 这样在相同的时间点我们就没法判断两个路径是否是相交的 于是在dp写挂 ...
- Linux 驱动框架---input子系统框架
前面从具体(Linux 驱动框架---input子系统)的工作过程学习了Linux的input子系统相关的架构知识,但是前面的学习比较实际缺少总结,所以今天就来总结一下输入子系统的架构分层,站到远处来 ...
- Bearer Token & OAuth 2.0
Bearer Token & OAuth 2.0 access token & refresh token http://localhost:8080/#/login HTTP Aut ...
- style element & web components
style element & web components style.textContent style.setContent bug style.textContent const st ...
- 封装 React Native 原生组件(iOS / Android)
封装 React Native 原生组件(iOS / Android) 在 React Native中,有很多种丰富的组件了,例如 ScrollView.FlatList.SectionList.Bu ...
- 扫码登录 & 实现原理
扫码登录 & 实现原理 二维码扫描登录是什么原理? https://time.geekbang.org/dailylesson/detail/100044032 xgqfrms 2012-20 ...
- nasm 函数返回一个数组 x86
getArguments.asm: extern VirtualAlloc section .text global dllmain export getArguments dllmain: mov ...
- 10000星光值兑换一个的VAST将如何搅动NGK算力市场?
加密数字货币是私人而非政府所发行的数字资产,具有自己的"货币"账户单位,在可以预见的未来三年之内,加密数字货币将覆盖至少全世界五分之一的人口.为此,NGK方面也做出了自己的努力,在 ...
- 聊一下PBN程序图例中的XTT
PBN航路点的定位容差用XTT与ATT来表示,ATT=0.8*XTT.保护区半宽用1.5*XTT+BV计算得到,BV值在不同的航段取值不同. 对于A至E类航空器,距ARP 30nm以外BV值为2 ...
- 【Python核心编程笔记】一、Python中一切皆对象
Python中一切皆对象 本章节首先对比静态语言以及动态语言,然后介绍 python 中最底层也是面向对象最重要的几个概念-object.type和class之间的关系,以此来引出在python如何做 ...