以np.concatenate为主题,谈谈numpy数组按维度合并的问题

1.引言

最近在做多模态融合的图像问题,其中最需要解决的就是不同模态的图像用什么方法进行融合,最简单也最直观的方法就是采用合并数组的方法,将不同模态的图像合并为多通道进行处理。在一些论文中,比如《Deep Learning-Based Image Segmentation on Multimodal Medical Imaging》中,如图1.1所示,论文中发现简单的concat 成多通道进行处理反而会比经过一部分网络提取特征后再融合效果更好。不过不同的情况需要具体分析,在《FusionNet: Incorporating Shape and Texture for Abnormality Detection in 3D Abdominal CT Scans》中,文章进行了多种组合的实验(不是模态融合,而是图片和mask的组合),结果发现某一种组合的效果最好。

 

 

 

图1.1 文章中提到的融合网络结构以及效果

 

 

不过总的来说,能够使用concat进行合并数组肯定是快速而有效的一种模态融合方法。

2.简要解析np.concatente官方文档

参见https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.concatenate.html

numpy.concatenate((a1a2…)axis=0out=None)

Join a sequence of arrays along an existing axis.

Parameters:
a1, a2, … sequence of array_like

The arrays must have the same shape, except in the dimension corresponding to axis (the first, by default).

axis int, optional

The axis along which the arrays will be joined. If axis is None, arrays are flattened before use. Default is 0.

out ndarray, optional

If provided, the destination to place the result. The shape must be correct, matching that of what concatenate would have returned if no out argument were specified.

Returns:
res ndarray

The concatenated array.

concatenate中含有两个参数,第一个参数是一个元组,元组里填入你想合并的数组,第二个参数是axis轴,第一个参数没什么好说的,主要想谈第二个参数。

另外要提的是官方提示,这个对我来说没什么用。

注意:当要串联的一个或多个数组为MaskedArray时,此函数将返回MaskedArray对象而不是ndarray,但不会保留输入掩码。 如果需要使用MaskedArray作为输入,请改用MaskedArray模块中的ma.concatenate函数。

正常的数组例子

>>> a = np.array([[1, 2], [3, 4]])  >>> b = np.array([[5, 6]])  >>> np.concatenate((a, b), axis=0)  array([[1, 2],         [3, 4],         [5, 6]])  >>> np.concatenate((a, b.T), axis=1)  array([[1, 2, 5],         [3, 4, 6]])  >>> np.concatenate((a, b), axis=None)  array([1, 2, 3, 4, 5, 6])  

 

 数组是MaskedArray时的例子,此函数将不会保留MaskedArray输入的掩码,要保留的话要用ma那个函数。

>>> a = np.ma.arange(3)  >>> a[1] = np.ma.masked  >>> b = np.arange(2, 5)  >>> a  masked_array(data = [0 -- 2],               mask = [False  True False],         fill_value = 999999)  >>> b  array([2, 3, 4])  >>> np.concatenate([a, b])  masked_array(data = [0 1 2 2 3 4],               mask = False,         fill_value = 999999)  >>> np.ma.concatenate([a, b])  masked_array(data = [0 -- 2 2 3 4],               mask = [False  True False False False False],         fill_value = 999999)  

  

3.axis的轴到底指的是什么

网上大多介绍的是一维数组和二维数组,但是很少提到高维数组的情况,

比如说当axis=0时,这时候就是np.concatenate指的是水平合并数组,当axi=1时,指的是垂直方向合并数组,举个例子:

定义两个数组:

a  array([0, 1, 2],         [3, 4, 5],         [6, 7, 8])  b = a*2  b  array([ 0, 2, 4],         [ 6, 8, 10],         [12, 14, 16])  

  下面进行合并:

np.hstack((a,b))  array([ 0, 1, 2, 0, 2, 4],         [ 3, 4, 5, 6, 8, 10],         [ 6, 7, 8, 12, 14, 16])    np.concatenate((a,b),axis=1)  array([ 0, 1, 2, 0, 2, 4],         [ 3, 4, 5, 6, 8, 10],         [ 6, 7, 8, 12, 14, 16])
np.vstack((a,b))  array([ 0, 1, 2],         [ 3, 4, 5],         [ 6, 7, 8],         [ 0, 2, 4],         [ 6, 8, 10],         [12, 14, 16])    np.concatenate((a,b),axis=0)  array([ 0, 1, 2],         [ 3, 4, 5],         [ 6, 7, 8],         [ 0, 2, 4],         [ 6, 8, 10],         [12, 14, 16])

 两种方式分别和np中的hstack以及vstack的合并数组的结果相同,那么concatenate存在的意义到底是什么呢,就在于它可以进行更高维度的数组合并。

就对我的问题而言,我要对两种模态的3d切片数据进行合并,两个数据的shape均为(10,1,128,128),如果我使用axis=1,那么不是进行垂直合并,而是选择了第二维度进行合并,比如说下面这个例子,最终输出的结果就是一个(10,2,128,128)的数组。

#coding=utf-8  import numpy as np    np.random.seed(0)  a = np.random.randint(0, 255, (10, 1, 128, 128))  b = np.random.randint(0, 255, (10, 1, 128,128))  ab = np.concatenate((a,b),axis = 1)  print('ab的维度为 = n {}'.format(ab.shape))

ab的维度为 = (10, 2, 128, 128)

 

这就一目了然了,原来np.concatenate并不仅仅是水平和垂直合并,而是多个维度的合并,axis轴的选择其实就是对某一个维度的选择。


那么进行数据融合的适合就方便多了,不过要解决先让数据进入网络后再提取特征进行fusion训练就是另一个问题了,我们下次再考虑。