Python:取非矩形区域的GLCM
Python: taking the GLCM of a non-rectangular region
我一直在使用 skimage 的 SLIC 实现来分割超像素的图像。我想使用 GLCM 从这些超像素中提取额外的特征来解决分类问题。这些超像素不是矩形的。在 MATLAB 中,您可以将像素设置为 NaN,算法将忽略它们 (link)。我可以使用它在超像素周围制作边界框,然后将未使用的像素设置为 NaN。
然而,skimage 中的 greycomatrix 函数与 MATLAB 实现并不完全相同。将像素设置为 NaN 时,该函数无法通过断言检查所有值是否都大于 0。
是否有能够使用非矩形 ROI 的 Python 实现?
问题是您必须将整数数组传递给 greycomatrix
,但 np.nan
的类型为 float
(请查看 了解详细信息)。因此,您无法将 ROI 之外的像素编码为 NaN
.
处理非矩形 ROI 的近似解决方法是将 ROI 外的像素设置为 0
并使用 mahotas 库中的函数 haralick
。这个函数 returns 从四个不同的 GLCM 中提取的 13 个 Haralick 特征,对应于四个二维方向和距离参数的特定值。
来自文档:
ignore_zeros
can be used to have the function ignore any zero-valued
pixels (as background).
综上所述,您需要屏蔽那些落在 ROI 之外的像素,并在对 haralick
的调用中将 ignore_zeros
设置为 True
。
演示版
首先,让我们生成一些模拟数据:
In [213]: import numpy as np
In [214]: shape = (3, 4)
In [215]: levels = 8
In [216]: np.random.seed(2017)
In [217]: x = np.random.randint(0, levels, size=shape)
In [218]: x
Out[218]:
array([[3, 1, 6, 5],
[2, 0, 2, 2],
[3, 7, 7, 7]])
然后我们必须从图像中删除所有零,因为在这种方法中,零强度级别是为 ROI 之外的像素保留的。值得指出的是,将强度 0
和 1
合并为一个强度 1
会导致结果不准确。
In [219]: x[x == 0] = 1
In [220]: x
Out[220]:
array([[3, 1, 6, 5],
[2, 1, 2, 2],
[3, 7, 7, 7]])
下一步包括为 ROI 之外的像素定义掩码(在这个玩具示例中,图像的四个角)并将这些像素设置为 0
。
In [221]: non_roi = np.zeros(shape=shape, dtype=np.bool)
In [222]: non_roi[np.ix_([0, -1], [0, -1])] = True
In [223]: non_roi
Out[223]:
array([[ True, False, False, True],
[False, False, False, False],
[ True, False, False, True]], dtype=bool)
In [224]: x[non_roi] = 0
In [225]: x
Out[225]:
array([[0, 1, 6, 0],
[2, 1, 2, 2],
[0, 7, 7, 0]])
我们现在可以从非矩形 ROI 的 GLCM 中提取特征:
In [226]: import mahotas.features.texture as mht
In [227]: features = mht.haralick(x, ignore_zeros=True)
In [228]: features.size
Out[228]: 52
In [229]: features.ravel()
Out[229]: array([ 0.18 , 5.4 , 0.5254833 , ..., 0.81127812,
-0.68810414, 0.96300727])
检查共现矩阵的外观可能很有用。例如,"pixel to the right" GLCM 将是:
In [230]: mht.cooccurence(x, 0)
Out[230]:
array([[0, 1, 0, ..., 0, 1, 2],
[1, 0, 2, ..., 0, 1, 0],
[0, 2, 2, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[1, 1, 0, ..., 0, 0, 0],
[2, 0, 0, ..., 0, 0, 2]])
虽然 mahotas
也是一个优秀的计算机视觉库,但没有必要停止使用 skimage
来做到这一点。
正如@Tonechas 指出的那样, 需要的是将这些 NaN 值设置为整数,因为 np.nan
的类型为 float
并且greycomatrix
函数需要一个整数数组。
最简单的选择是将那些 NaN
设置为零,但是,如果您的像素中已经有零值并且不想混合它们,您可以选择任何其他常量。之后,您所要做的就是从 GLCM 中过滤出所选值(同样,通常为零)。
为了理解这意味着什么,让我们看看 skimage
告诉我们关于 greycomatrix
function 的输出:
4-D ndarray
[...] The value P[i,j,d,theta] is the number of times that grey-level j occurs at a distance d and at an angle theta from grey-level i. If normed is False, the output is of type uint32, otherwise it is float64. The dimensions are: levels x levels x number of distances x number of angles.
换句话说,数组的前两个维度定义了一个矩阵,告诉我们有多少次两个不同的值相距一定距离。请注意,GLCM 确实 而不是 保持输入数组的形状。这些行和列告诉我们这些值是如何关联的。
了解这一点后,很容易过滤掉 ROI 之外的值(假设我们已将这些 NaN 设置为零):
glcm = greycomatrix(img, [1], [0]) # Calculate the GLCM "one pixel to the right"
filt_glcm = glcm[1:, 1:, :, :] # Filter out the first row and column
现在您可以轻松计算过滤后的 GLCM 的 Haralick 特性。例如:
greycoprops(filt_glcm, prop='contrast')
我一直在使用 skimage 的 SLIC 实现来分割超像素的图像。我想使用 GLCM 从这些超像素中提取额外的特征来解决分类问题。这些超像素不是矩形的。在 MATLAB 中,您可以将像素设置为 NaN,算法将忽略它们 (link)。我可以使用它在超像素周围制作边界框,然后将未使用的像素设置为 NaN。
然而,skimage 中的 greycomatrix 函数与 MATLAB 实现并不完全相同。将像素设置为 NaN 时,该函数无法通过断言检查所有值是否都大于 0。
是否有能够使用非矩形 ROI 的 Python 实现?
问题是您必须将整数数组传递给 greycomatrix
,但 np.nan
的类型为 float
(请查看 NaN
.
处理非矩形 ROI 的近似解决方法是将 ROI 外的像素设置为 0
并使用 mahotas 库中的函数 haralick
。这个函数 returns 从四个不同的 GLCM 中提取的 13 个 Haralick 特征,对应于四个二维方向和距离参数的特定值。
来自文档:
ignore_zeros
can be used to have the function ignore any zero-valued pixels (as background).
综上所述,您需要屏蔽那些落在 ROI 之外的像素,并在对 haralick
的调用中将 ignore_zeros
设置为 True
。
演示版
首先,让我们生成一些模拟数据:
In [213]: import numpy as np
In [214]: shape = (3, 4)
In [215]: levels = 8
In [216]: np.random.seed(2017)
In [217]: x = np.random.randint(0, levels, size=shape)
In [218]: x
Out[218]:
array([[3, 1, 6, 5],
[2, 0, 2, 2],
[3, 7, 7, 7]])
然后我们必须从图像中删除所有零,因为在这种方法中,零强度级别是为 ROI 之外的像素保留的。值得指出的是,将强度 0
和 1
合并为一个强度 1
会导致结果不准确。
In [219]: x[x == 0] = 1
In [220]: x
Out[220]:
array([[3, 1, 6, 5],
[2, 1, 2, 2],
[3, 7, 7, 7]])
下一步包括为 ROI 之外的像素定义掩码(在这个玩具示例中,图像的四个角)并将这些像素设置为 0
。
In [221]: non_roi = np.zeros(shape=shape, dtype=np.bool)
In [222]: non_roi[np.ix_([0, -1], [0, -1])] = True
In [223]: non_roi
Out[223]:
array([[ True, False, False, True],
[False, False, False, False],
[ True, False, False, True]], dtype=bool)
In [224]: x[non_roi] = 0
In [225]: x
Out[225]:
array([[0, 1, 6, 0],
[2, 1, 2, 2],
[0, 7, 7, 0]])
我们现在可以从非矩形 ROI 的 GLCM 中提取特征:
In [226]: import mahotas.features.texture as mht
In [227]: features = mht.haralick(x, ignore_zeros=True)
In [228]: features.size
Out[228]: 52
In [229]: features.ravel()
Out[229]: array([ 0.18 , 5.4 , 0.5254833 , ..., 0.81127812,
-0.68810414, 0.96300727])
检查共现矩阵的外观可能很有用。例如,"pixel to the right" GLCM 将是:
In [230]: mht.cooccurence(x, 0)
Out[230]:
array([[0, 1, 0, ..., 0, 1, 2],
[1, 0, 2, ..., 0, 1, 0],
[0, 2, 2, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[1, 1, 0, ..., 0, 0, 0],
[2, 0, 0, ..., 0, 0, 2]])
虽然 mahotas
也是一个优秀的计算机视觉库,但没有必要停止使用 skimage
来做到这一点。
正如@Tonechas 指出的那样, 需要的是将这些 NaN 值设置为整数,因为 np.nan
的类型为 float
并且greycomatrix
函数需要一个整数数组。
最简单的选择是将那些 NaN
设置为零,但是,如果您的像素中已经有零值并且不想混合它们,您可以选择任何其他常量。之后,您所要做的就是从 GLCM 中过滤出所选值(同样,通常为零)。
为了理解这意味着什么,让我们看看 skimage
告诉我们关于 greycomatrix
function 的输出:
4-D ndarray
[...] The value P[i,j,d,theta] is the number of times that grey-level j occurs at a distance d and at an angle theta from grey-level i. If normed is False, the output is of type uint32, otherwise it is float64. The dimensions are: levels x levels x number of distances x number of angles.
换句话说,数组的前两个维度定义了一个矩阵,告诉我们有多少次两个不同的值相距一定距离。请注意,GLCM 确实 而不是 保持输入数组的形状。这些行和列告诉我们这些值是如何关联的。
了解这一点后,很容易过滤掉 ROI 之外的值(假设我们已将这些 NaN 设置为零):
glcm = greycomatrix(img, [1], [0]) # Calculate the GLCM "one pixel to the right"
filt_glcm = glcm[1:, 1:, :, :] # Filter out the first row and column
现在您可以轻松计算过滤后的 GLCM 的 Haralick 特性。例如:
greycoprops(filt_glcm, prop='contrast')