图像匹配 | 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 ...
随机推荐
- fibonacci number & fibonacci sequence
fibonacci number & fibonacci sequence https://www.mathsisfun.com/numbers/fibonacci-sequence.html ...
- React Security Best Practices All In One
React Security Best Practices All In One Default XSS Protection with Data Binding Dangerous URLs Ren ...
- node.js 中间件
node.js 中间件 node.js middleware Express middleware body-parser cookie-parser cookie-session cors csur ...
- Scratch 游戏开发
Scratch 游戏开发 可视化少儿编程 https://scratch.mit.edu/ Scratch Desktop https://scratch.mit.edu/download https ...
- ESLint error level
ESLint error level https://eslint.org/docs/user-guide/getting-started#configuration .eslintrc { &quo ...
- 谁能成为数据储存领域领头羊?永久数据存储--NGK的终极使命!
区块链的目的是永远存储交易网络的历史.NGK技术团队能够永久存储其去中心化账本的副本.这是其日后能进行审计关键.一些著名的团队,如Solana和SKALE,现在正在为此与NGK进行最后的集成,我们预计 ...
- idea加载maven项目遇见的坑---2
idea每次加载完一个maven项目,都需要重新配置 file>>>Settings 然后继续找 还有就是配置项目的时候 配置项目jdk 最后需要注意,有时候你会发现都设置完了,但是 ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- ServiceMesh
传统微服务架构 在微服务模式下,企业内部服务少则几个到几十个,多则上百个,每个服务一般都以集群方式部署,这时自然产生两个问题: 一.服务发现:服务的消费方(Consumer)如何发现服务的提供方(Pr ...
- System.IO.IOException:“找不到资源“window1.xaml”。” 解决方法
报错:找不到资源"window1.xaml 原因:在编译时使用的是en-US选项进行编译并生成了en-US为名的文件夹,里面包含了可本地化的内容:但是你的本地系统使用的是zh-CN,在你运行 ...