MIND——Modality independent neighbourhood descriptor 模态无关邻域描述符

news2024/10/2 6:38:50

参考:

https://blog.mbedded.ninja/programming/signal-processing/image-processing/image-registration/modality-independent-neighbourhood-descriptor-mind/

《MIND: Modality independent neighbourhood descriptor for multi-modal deformable registration》论文

2D版的MIND_shchojj的博客-CSDN博客

MIND(模态独立邻域描述符)是一种图像配准算法,旨在提取每个像素/体素周围局部区域的结构信息。

一、原理介绍

1、公式介绍

MIND表达式如下:

Dp(I,x,x+r)指以x点为中心的Patch块和以x+r为中心的Patch块的距离,即两个Patch块之差的平方。

V(I,x)是指图像中x点的6邻域搜索空间内各点的Dp(I,x,x+r)相加再平均。(这个邻域搜索空间后面介绍)

MIND(I,x,r)是感兴趣点x的邻域搜索空间内这n个点的Dp(I,x,x+r)除以该点的V(I,x),再负对数。

邻域搜索空间neigh Search Space:分为三种

紧密型采样(全采样) 稀疏性采样(45°采样) 6邻域采样

*红色小块为感兴趣点,即需要求MIND特征的像素点。

如果设置一个5*5的一个neigh,紧密型采样的邻域搜索空间包括除红色像素以外的所有灰色像素点;稀疏型采样同理如中图所示;6邻域采样应该是文章针对三维图像来讲的,对于二维的图像,应该也可以说是4邻域。

Patch:3*3的patch是指一个3*3的像素小块

2、图示说明

从一个5*5的像素块开始理解:

*蓝色像素4的地方是感兴趣点,即正要计算MIND特征的像素点,

*靛青色像素是设置的4邻域搜索空间

开始计算之前,先设置参数patch(3*3),neigh(3*3,4邻域采样)

(1)4邻域搜索空间内各点的Dp(I,x,x+r)

向量x=(1,2),向量x+r={(1,1),(0,2),(1,3),(2,2)}

同理求完四个点的Dp(I,x,x+r)如下图所示:

(2)求V(I,x)

V(I,x)在2维图像中需要求4邻域搜索空间的4个点的Dp(I,x,x+r)的平均

到这里只求得了一个像素点(1,2)的V(I,x),对于整个5*5的像素块或者256*256的图像,我们就需要求出这个像素块或者图像的V(I,x)的一个矩阵。

array([[ 15.33,  41.97,  68.19,  87.61,  60.97],
       [ 47.06,  93.78, 126.25, 137.28,  90.56],
       [ 93.72, 141.75, 157.06, 129.78,  81.75],
       [109.42, 147.36, 152.08,  99.03,  61.08],
       [ 77.69,  95.56,  94.03,  49.36,  31.5 ]])

(3)计算MIND特征

那么MIND(I,(1,2))=[0.300,0.275,0.361,0.616]

同样到这里,我们只获得了点(1,2)的MIND特征,而对于这个5*5的像素块,我们还要获得其余24个点的MIND特征。

最终得到的这个5*5的像素块的MIND特征如下:

mind_descriptors =
  array([
       [[0.199, 0.404, 0.258, 0.884],
        [0.142, 0.554, 0.381, 0.611],
        [0.354, 0.301, 0.408, 0.421],
        [0.505, 0.446, 0.265, 0.307],
        [0.955, 0.374, 0.205, 0.25 ]],

       [[0.367, 0.615, 0.126, 0.643],
        [0.176, 0.604, 0.266, 0.649],
        [0.3  , 0.275, 0.361, 0.616],
        [0.395, 0.33 , 0.328, 0.428],
        [0.878, 0.244, 0.248, 0.344]],

       [[0.43 , 0.845, 0.142, 0.354],
        [0.301, 0.572, 0.255, 0.416],
        [0.326, 0.339, 0.377, 0.44 ],
        [0.419, 0.257, 0.552, 0.308],
        [0.765, 0.251, 0.445, 0.214]],

       [[0.49 , 0.887, 0.224, 0.188],
        [0.376, 0.589, 0.308, 0.269],
        [0.349, 0.388, 0.371, 0.365],
        [0.383, 0.199, 0.525, 0.46 ],
        [0.621, 0.211, 0.413, 0.339]],

       [[0.488, 0.948, 0.325, 0.121],
        [0.518, 0.558, 0.39 , 0.162],
        [0.432, 0.512, 0.412, 0.201],
        [0.575, 0.202, 0.575, 0.274],
        [0.528, 0.42 , 0.459, 0.18 ]]])

如果想要比较一个5*5和像素块A和一个5*5的像素块B的结构相似性,那么就要先获得A和B的形状为(5,5,4)的MIND特征矩阵。然后将每个像素点的对应的MIND矩阵加和作为该像素点的MIND特征,最后就又会得到A的5*5的MIND特征图和B的MIND特征图。论文中的MIND特征图展示如下:

二、Python实现代码Pytorch(2D版)

import torch
import numpy as np
import torchvision
import SimpleITK as sitk
import torch.nn.functional as F
import matplotlib.pyplot as plt
def gaussian_kernel(sigma, sz):
    xpos_vec = np.arange(sz)
    ypos_vec = np.arange(sz)
    output = np.ones([1, 1,sz, sz], dtype=np.single)
    midpos = sz // 2
    for xpos in xpos_vec:
        for ypos in ypos_vec:
            output[:,:,xpos,ypos] = np.exp(-((xpos-midpos)**2 + (ypos-midpos)**2) / (2 * sigma**2)) / (2 * np.pi * sigma**2)
    return output
def torch_image_translate(input_, tx, ty, interpolation='nearest'):
    # got these parameters from solving the equations for pixel translations
    # on https://www.tensorflow.org/api_docs/python/tf/contrib/image/transform
    translation_matrix = torch.zeros([1, 3, 3], dtype=torch.float)
    translation_matrix[:, 0, 0] = 1.0
    translation_matrix[:, 1, 1] = 1.0
    translation_matrix[:, 0, 2] = -2*tx/(input_.size()[2]-1)
    translation_matrix[:, 1, 2] = -2*ty/(input_.size()[3]-1)
    translation_matrix[:, 2, 2] = 1.0
    grid = F.affine_grid(translation_matrix[:, 0:2, :], input_.size()).to(input_.device)
    wrp = F.grid_sample(input_, grid, mode=interpolation)
    return wrp
def Dp(image, xshift, yshift, sigma, patch_size):
    shift_image = torch_image_translate(image, xshift, yshift, interpolation='nearest')#将image在x、y方向移动I`(a)
    diff = torch.sub(image, shift_image)#计算差分图I-I`(a)
    diff_square = torch.mul(diff, diff)#(I-I`(a))^2
    res = torch.conv2d(diff_square, weight =torch.from_numpy(gaussian_kernel(sigma, patch_size)), stride=1, padding=3)#C*(I-I`(a))^2
    return res
 
def MIND(image, patch_size, neigh_size, sigma, eps,image_size0,image_size1,  name='MIND'):
    # compute the Modality independent neighbourhood descriptor (MIND) of input image.
    # suppose the neighbor size is R, patch size is P.
    # input image is 384 x 256 x input_c_dim
    # output MIND is (384-P-R+2) x (256-P-R+2) x R*R
    reduce_size = int((patch_size + neigh_size - 2) / 2)#卷积后减少的size
 
    # estimate the local variance of each pixel within the input image.
    Vimg = torch.add(Dp(image, -1, 0, sigma, patch_size), Dp(image, 1, 0, sigma, patch_size))
    Vimg = torch.add(Vimg, Dp(image, 0, -1, sigma, patch_size))
    Vimg = torch.add(Vimg, Dp(image, 0, 1, sigma, patch_size))#sum(Dp)
    Vimg = torch.div(Vimg,4) + torch.mul(torch.ones_like(Vimg), eps)#防除零
    # estimate the (R*R)-length MIND feature by shifting the input image by R*R times.
    xshift_vec = np.arange( -(neigh_size//2), neigh_size - (neigh_size//2))#邻域计算
    yshift_vec = np.arange(-(neigh_size // 2), neigh_size - (neigh_size // 2))#邻域计算
    iter_pos = 0
    for xshift in xshift_vec:
        for yshift in yshift_vec:
            if (xshift,yshift) == (0,0):
                continue
            MIND_tmp = torch.exp(torch.mul(torch.div(Dp(image, xshift, yshift,  sigma, patch_size), Vimg), -1))#exp(-D(I)/V(I))
            tmp = MIND_tmp[:, :, reduce_size:(image_size0 - reduce_size), reduce_size:(image_size1 - reduce_size)]
            if iter_pos == 0:
                output = tmp
            else:
                output = torch.cat([output,tmp], 1)
            iter_pos = iter_pos + 1
 
    # normalization.
    input_max, input_indexes = torch.max(output, dim=1)
    output = torch.div(output,input_max)
 
    return output
def abs_criterion(in_, target):
    return torch.mean(torch.abs(in_ - target))
if __name__ == '__main__':
    patch_size=7
    neigh_size=9
    sigma=2.0
    eps=1e-5
    image_size0=512
    image_size1=512
    ct_path = r'F:\dataset\coarseReg\00001_SRO1_ct_axial_drr.nii.gz'
    mr_path = r'F:\dataset\coarseReg\00001_SRO1_mr_axial_drr.nii.gz'
    ct_sitk = sitk.ReadImage(ct_path,sitk.sitkFloat32)
    mr_sitk = sitk.ReadImage(mr_path,sitk.sitkFloat32)
 
    ct_axial_drr = sitk.GetArrayFromImage(ct_sitk)[np.newaxis ,np.newaxis,:,:]
    mr_axial_drr = sitk.GetArrayFromImage(mr_sitk)[np.newaxis ,np.newaxis,:,: ]
 
    plt.imshow(ct_axial_drr.squeeze())
    plt.show()
 
    ct_axial_drr = torch.from_numpy(ct_axial_drr)
    mr_axial_drr = torch.from_numpy(mr_axial_drr)
 
    A_MIND = MIND(ct_axial_drr,  patch_size, neigh_size, sigma, eps,image_size0,image_size1,  name='realA_MIND')
    B_MIND = MIND(mr_axial_drr,  patch_size, neigh_size, sigma, eps,image_size0,image_size1,  name='realA_MIND')
    g_loss_MIND = abs_criterion(A_MIND, B_MIND)
    print('g_loss_MIND', g_loss_MIND)
 
    # tf =  np.load( r"C:\Users\shcho\Desktop\validation\tf.npy" )
    # tc =  np.load( r"C:\Users\shcho\Desktop\validation\tc.npy" )
 
    # plt.imshow(tf)
    # plt.show()
    # plt.imshow(tc)
    # plt.show()
    # print(tf.shape, tc.shape)
    #
    # # print(tf.transpose((2,0,1)).shape, tc.shape)
    # t = tf.transpose((2,0,1)) -tc
    #
    # # t = tf -tc
    #
    # print(np.max(t))

可以通过上面代码提取整张图像的MIND特征,且该函数可以被用于基于CycleGAN网络处理MRtoCT图像的损失函数并得到很好的结果,如论文《Unsupervised MR-to-CT Synthesis using Structure Constrained CycleGAN》所述,同理可用于相似的CycleGAN网络模型处理医学图像的任务中来约束A,B域的结构信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/369945.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【离线数仓-6-数据仓库开发ODS层设计要点】

离线数仓-6-数据仓库开发ODS层设计要点离线数仓-6-数据仓库开发ODS层1.数据仓库开发ODS层设计要点2.ODS层用户行为日志表1.hive中复杂结构体复习1.array2.map3.struct 复杂结构4.嵌套格式2.hive中针对复杂结构字符串的练习1.针对ods层为json格式数据的练习2.用户行为日志表的设…

Linux学习(5)nano与正确关机方法sync shutdown

目录 文书编辑器 nano 正确的关机方法: sync, shutdown, reboot, halt, poweroff, init 数据同步写入磁盘:sync 惯用的关机命令: shutdown 重新启动,关机: reboot, halt, poweroff 切换运行等级: init 以下内容转载…

linux编程之经典多级时间轮定时器(C语言版)

一. 多级时间轮实现框架 上图是5个时间轮级联的效果图。中间的大轮是工作轮,只有在它上的任务才会被执行;其他轮上的任务时间到后迁移到下一级轮上,他们最终都会迁移到工作轮上而被调度执行。 多级时间轮的原理也容易理解:就拿时…

技术分享| anyRTC回声消除算法进化

本文将从基础概念、经典算法、主要挑战,以及人工智能回声消除技术探索等方面,分享anyRTC在 AEC 技术方面的实践及效果。 一.什么是回声消除 回音消除一直是语音通信的难点,最早的回声消除是从电话兴起的时候就有了,电话机的硬件…

postgres 源码解析51 LWLock轻量锁--2

本篇将着重讲解LWLock涉及的主要API工作流程与实现原理,相关基础知识见回顾:postgres 源码解析50 LWLock轻量锁–1 API介绍 函数API功能CreateLWLocks分配LWLocks所需的内存并进行初始化LWLockNewTrancheId分配新的Tranche ID,供用户使用Extension模块…

Helm安装Harbor

一、介绍 1.1 Harbor Harbor 是由 VMware 公司为企业用户设计的 Registry Server 开源项目,包括了权限管理 (RBAC)、LDAP、审计、管理界面、自我注册、HA 等企业必需的功能,同时针对中国用户的特点,设计镜像复制和中文支持等功能。目前该项…

说说Java“锁“ 事

文章目录前言大厂面试题复盘 —— 并发编程高级面试解析从轻松的乐观锁和悲观锁开讲通过8种情况演示锁运行案例,看看我们到底锁的是什么公平锁和非公平锁可重入锁(又名递归锁)死锁及排查写锁(独占锁)/读锁(共享锁)自旋锁SpinLock无锁 -> 独占锁 -> 读写锁 -&g…

五种IO模型以及select多路转接IO模型

目录 一、典型IO模型 1.1 阻塞IO 1.2 非阻塞IO 1.3 信号驱动I0 1.4 IO多路转接 1.5 异步IO 多路转接的作用和意义 二、多路转接IO模型(select) 2.1 接口 2.2 接口当中的事件集合: fd_set 2.2 select使用事件集合(位图&am…

ip公司和soc公司是什么?

IP 公司和 SoC 公司都是半导体行业的重要组成部分,但它们的角色和职责略有不同。IP(Intellectual Property)公司主要提供可重用的知识产权组件,也称为 IP 核或 IP 模块,这些组件可以在设计芯片的过程中被集成到芯片中。…

Git代码冲突-不同分支之间的代码冲突

1、解决思路在团队开发中,提交代码到Git仓库时经常会遇到代码冲突的问题。- 原因:多人对相同的文件进行了编辑,造成代码存在差异化- 解决方案:1. 使用工具或git命令对比不同分支代码的差异化2. 把不同分支中有效代码进行保留&…

[译文] 基于PostGIS3.1 生成格网数据

根据格网进行数据统计与分析是一种常用的方法,相比自然地理边界与行政管理边界而言,使用格网有如下特点:每个格网之间地位相等,没有上下级之分。每个格网的面积都相等。相邻两个格网单元中心点之间距离相等。适用于将数据从“空间…

ThreeJS加载公路GeoJson数据实现流光效果

threejs加载公路geojson数据,跟加载行政区域的原理一样,唯一不同的是geojson格式不一样,路线并不是连贯起来的,按照路段进行的拆分,在加载的时候问题不大,正常解析然后转墨卡托投影,但是在做流光效果时,需要对geojson进行重新组合. 实现效果:

Android:反编译apk踩坑/apktool/dex2jar/JDGUI

需求描述 想要反编译apk文件,搜到了这篇博客:Android APK反编译就这么简单 详解(附图),非常有参考价值~但其中的工具下载链接都已404,而本杂鱼实际操作的过程中也出现了亿点点点点点点的问题,于…

电子技术——反馈对放大器极点的影响

电子技术——反馈对放大器极点的影响 放大器的频率响应和稳定性可以直接由其极点决定。因此我们将深入反馈对放大器极点的影响。 稳定性和极点位置 我们首先讨论稳定性和极点位置的关系。首先我们给出结论,对于任何一个稳定的放大器,其极点都处在 sss …

prometheus + alterManager + 飞书通知,实现服务宕机监控告警;实测可用

架构设计图 最终效果图 项目准备 xml依赖 <!-- 监控相关 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>io.…

Elasticsearch7.8.0版本进阶——段合并

目录一、段的概述1.1、段的概念1.2、段的缺点1.3、如何解决段数量暴增问题二、段合并的流程三、段合并的注意事项一、段的概述 1.1、段的概念 每一 段 本身都是一个倒排索引。 1.2、段的缺点 由于自动刷新流程每秒会创建一个新的段 &#xff0c;这样会导致短时间内的段数量…

interrupt多线程设计模式

1. 两阶段终止-interrupt Two Phase Termination 在一个线程T1中如何“优雅”终止线程T2&#xff1f;这里的【优雅】指的是给T2一个料理后事的机会。 错误思路 ● 使用线程对象的stop()方法停止线程&#xff08;强制杀死&#xff09; —— stop&#xff08;&#xff09;方法…

Linux内核的虚拟内存(MMU、页表结构)

前言&#xff1a;内存是程序得以运行的重要物质基础。如何在有限的内存空间运行较大的应用程序&#xff0c;曾是困扰人们的一个难题。为解决这个问题&#xff0c;人们设计了许多的方案&#xff0c;其中最成功的当属虚拟内存技术。Linux作为一个以通用为目的的现代大型操作系统&…

【git】Idea中git的使用

配置git 创建git仓库 不同颜色代表的含义 红色——未加入版本控制&#xff1b;绿色——已经加入控制暂未提交&#xff1b;蓝色——加入&#xff0c;已提交&#xff0c;有改动&#xff1b;白色——加入&#xff0c;已提交&#xff0c;无改动&#xff1b;灰色——版本控制已忽略文…

8、STM32 FSMC驱动LCD(ILI93xx)

本文使用FSMC驱动LCD显示&#xff0c;关于建议先看之前的7、STM32 FSMC驱动SRAM一文 硬件连接&#xff1a; 一、CubeMx配置FSMC驱动LCD ILI93xx 此章只为快速使用LCD&#xff0c;不涉及原理、指令说明 显示屏驱动文件参考正点探索者 1、CubeMx图形配置 此处的时序还可以调…