• 文章转载自:微信公众号「机器学习炼丹术」
  • 作者:炼丹兄(已授权)
  • 作者联系方式:微信cyx645016617(欢迎交流共同进步)

本次的内容主要讲解NCCNormalized cross-correlation 归一化互相关。

两张图片是否是同一个内容,现在深度学习的方案自然是用神经网络,比方说:孪生网络的架构做人面识别等等;

在传统的非参数方法中,常见的也有相关系数等。我在上一片文章voxelmorph的模型的学习中发现,在医学图像配准任务(不限于医学),衡量两个图片相似的度量有一种叫做NCC的

而这个NCC就是Normalized Cross-Correlation归一化互相关系数。

1 互相关系数

如果你知道互相关系数,那么你就能很好的理解归一化互相关系数。

相关系数的计算公式如下:

\[r(X,Y) = \frac{Cov(X,Y)}{\sqrt{Var(X)Var(Y)}}
\]

公式中的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 归一化互相关损失 | 代码 + 讲解的更多相关文章

  1. 第二章--Win32程序运行原理 (部分概念及代码讲解)

    学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...

  2. 『HTML5实现人工智能』小游戏《井字棋》发布,据说IQ上200才能赢【算法&代码讲解+资源打包下载】

    一,什么是TicTacToe(井字棋) 本游戏为在下用lufylegend开发的第二款小游戏.此游戏是大家想必大家小时候都玩过,因为玩它很简单,只需要一张草稿纸和一只笔就能开始游戏,所以广受儿童欢迎. ...

  3. Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解

    Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解 说明:Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解,实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返 ...

  4. faster RCNN(keras版本)代码讲解(3)-训练流程详情

    转载:https://blog.csdn.net/u011311291/article/details/81121519 https://blog.csdn.net/qq_34564612/artic ...

  5. 毕业设计java实验室预约管理系统SSH机房预约系统javaweb机房实验室排课系统mysql机房管理系统 实验室管理系统 课程设计 代码讲解 调试运行

    毕业设计java实验室预约管理系统SSH机房预约系统javaweb机房实验室排课系统mysql机房管理系统 实验室管理系统 课程设计 代码讲解 调试运行 注意:该项目只展示部分功能,如需了解,评论区咨 ...

  6. 双目立体匹配——归一化互相关(NCC)

    归一化相关性,normalization cross-correlation,因此简称NCC,下文中笔者将用NCC来代替这冗长的名称. NCC,顾名思义,就是用于归一化待匹配目标之间的相关程度,注意这 ...

  7. CUDA学习,第一个kernel函数及代码讲解

    前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...

  8. 李宏毅 Gradient Descent Demo 代码讲解

    何为梯度下降,直白点就是,链式求导法则,不断更新变量值. 这里讲解的代码为李宏毅老师机器学习课程中 class 4 回归展示 中的代码demo   Loss函数 python代码如下 import n ...

  9. Widget代码讲解

    参考:https://zhuanlan.zhihu.com/p/28225011 QT版本为5.12.4 1.main.cpp #include "widget.h" #inclu ...

随机推荐

  1. fibonacci number & fibonacci sequence

    fibonacci number & fibonacci sequence https://www.mathsisfun.com/numbers/fibonacci-sequence.html ...

  2. React Security Best Practices All In One

    React Security Best Practices All In One Default XSS Protection with Data Binding Dangerous URLs Ren ...

  3. node.js 中间件

    node.js 中间件 node.js middleware Express middleware body-parser cookie-parser cookie-session cors csur ...

  4. Scratch 游戏开发

    Scratch 游戏开发 可视化少儿编程 https://scratch.mit.edu/ Scratch Desktop https://scratch.mit.edu/download https ...

  5. ESLint error level

    ESLint error level https://eslint.org/docs/user-guide/getting-started#configuration .eslintrc { &quo ...

  6. 谁能成为数据储存领域领头羊?永久数据存储--NGK的终极使命!

    区块链的目的是永远存储交易网络的历史.NGK技术团队能够永久存储其去中心化账本的副本.这是其日后能进行审计关键.一些著名的团队,如Solana和SKALE,现在正在为此与NGK进行最后的集成,我们预计 ...

  7. idea加载maven项目遇见的坑---2

    idea每次加载完一个maven项目,都需要重新配置 file>>>Settings 然后继续找 还有就是配置项目的时候 配置项目jdk 最后需要注意,有时候你会发现都设置完了,但是 ...

  8. 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  9. ServiceMesh

    传统微服务架构 在微服务模式下,企业内部服务少则几个到几十个,多则上百个,每个服务一般都以集群方式部署,这时自然产生两个问题: 一.服务发现:服务的消费方(Consumer)如何发现服务的提供方(Pr ...

  10. System.IO.IOException:“找不到资源“window1.xaml”。” 解决方法

    报错:找不到资源"window1.xaml 原因:在编译时使用的是en-US选项进行编译并生成了en-US为名的文件夹,里面包含了可本地化的内容:但是你的本地系统使用的是zh-CN,在你运行 ...