• 文章转载自:微信公众号「机器学习炼丹术」
  • 作者:炼丹兄(已授权)
  • 作者联系方式:微信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. JavaScript事件绑定的三种方式

    (一)事件绑定的三种方式 (1)通过on的形式 <script type="text/javascript"> var div = document.getElemen ...

  2. Scalability & Scale-up & Scale-out

    Scalability & Scale-up & Scale-out 架构,弹性,伸缩性 Scalability 可扩展性 https://en.wikipedia.org/wiki/ ...

  3. UI 素材网站

    UI 素材网站 UI 设计师网站 国外: dribble.behance.Pinteres 国内: 优设.站酷.UI中国.花瓣 https://design.google/ https://dribb ...

  4. Flutter 在mixin中使用setState

    相关问题 创建mixin import 'package:flutter/material.dart'; mixin JobsMixin<T extends StatefulWidget> ...

  5. js字典

    传送门https://www.2cto.com/kf/201709/680989.html 点击

  6. 使用docker mediawiki,搭建网页wiki

    我只是想做一个大家都能访问的wiki,用于成员间共享和维护一些文档.找到了docker的mediawiki,这里记录一下我怎么搭的吧. 首先,如果你在一个局域网里,有公用的可以访问的服务器,那可以直接 ...

  7. Java ThreadPoolExecutor详解

    ThreadPoolExecutor是Java语言对于线程池的实现.池化技术是一种复用资源,减少开销的技术.线程是操作系统的资源,线程的创建与调度由操作系统负责,线程的创建与调度都要耗费大量的资源,其 ...

  8. The last packet successfully received from the server was 49,061,696 millise

    解决连接:https://blog.csdn.net/pandajava/article/details/41946251

  9. vue之provide和inject跨组件传递属性值失败(父组件向子组件传值的两种方式)

    简单介绍:当一个子组件需要用到父组件的父组件的某些参数.那么这个时候为了避免组件重复传参,使用vue的依赖注入是个不错的方法,直接在最外层组件设置一个provide,内部不管多少嵌套都可以直接取到最外 ...

  10. Virtual DOM 简直就是挥霍

    彻底澄清"Virtual DOM 飞快"的神话. 注意:原文发表于2018-12-27,随着框架不断演进,部分内容可能已不适用. 近年来,如果你有使用过 JavaScript 框架 ...