我正在尝试提取图像蒙版的两个区域的索引/位置,我正在使用python,opencv2,numpy和scipy的组合。
我有一个二进制mask
,其大小与图像相同。
用
label_im, nb_labels = ndimage.label(mask)
sizes = ndimage.sum(mask, label_im, range(nb_labels + 1))
通过这些信息,我能够提取最大的区域。
假设我们有一个10x10矩阵:
1 1 1 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0
1 1 1 0 0 0 0 2 2 0
0 0 0 0 0 0 0 2 2 0
0 3 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
我有3个不同的区域(1,2,3),我已经知道,我需要进一步分析区域2和区域3(因为它们是最大的区域)。
现在我想找到像素
的索引与上述相同的矩阵:
1 1 1 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0
1 1 1 0 0 0 0 (2) 2 0
0 0 0 0 0 0 0 2 2 0
0 (3) 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 2 2 0
0 3 3 3 3 0 0 2 [2] 0
0 3 3 3 [3] 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
最快的方法是如何做到的?
问题1: 我正在努力解决这些矩阵条件的语法问题。 例如,我尝试:
mask2 = mask[label_im == 2]
它应该再次获得二进制掩码,但只设置原始掩码为2的单元格。 我不确定上面产生的结果是什么。而且我因此无法进一步处理它。
问题2: 在那之后,我将不得不做一些事情,比如找到最顶层像素设置的行/列的索引。 与最低点相同。
例如,对于区域2,结果应为:(如上面的矩阵)
point1-X = 7
point1-Y = 2
point2-X = 8
point2-Y = 7
其中X代表列,Y代表行(从索引0开始)
或者有更好的方法来解决像python / opencv2 / numpy / scipy这样的问题吗?
答案 0 :(得分:1)
基于NumPy的解决方案
在输入图像数组的展平版本上,topmost leftmost
位置将是第一个,而lowermost rightmost
将是最后一个。因此,一个技巧是使用np.nonzero
获得这两个区域的扁平索引,并简单地查找min
和max
索引以分别获得这些预期输出。最后,我们将使用np.unravel_index
检索与原始2D
格式对应的后行col参数。
因此,一种方法是 -
# Flattend indices for those two regions using the given labels
idx0 = np.nonzero(a.ravel()==2)[0]
idx1 = np.nonzero(a.ravel()==3)[0]
# Get the min, max indices for them. Use np.unravel_index to retrieve
# back row, col indices corresponding to original format of 2D input.
idxs = [idx0.min(), idx0.max(), idx1.min(), idx1.max()]
out = np.column_stack(np.unravel_index(idxs,a.shape))
示例运行 -
In [137]: a
Out[137]:
array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 2, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
In [138]: idx0 = np.nonzero(a.ravel()==2)[0]
...: idx1 = np.nonzero(a.ravel()==3)[0]
...: idxs = [idx0.min(), idx0.max(), idx1.min(), idx1.max()]
...: out = np.column_stack(np.unravel_index(idxs,a.shape))
...:
In [139]: out
Out[139]:
array([[2, 7], # topmost leftmost of region -1
[7, 8], # lowermost rightmost of region -1
[4, 1], # topmost leftmost of region -2
[8, 4]]) # lowermost rightmost of region -2
基于OpenCV的解决方案
OpenCV的cv2.findContours
可用于查找轮廓,这本身就是一种非常有效的实现。因此,我们将仅针对面向绩效的解决方案限制对轮廓的索引的发现。下面显示的是获取每个地区的topmost leftmost
和lowermost rightmost
行,列索引的函数 -
def TL_LR(a, label):
_,contours,hierarchy = cv2.findContours((a==label).astype('uint8'),\
cv2.RETR_TREE,cv2.RETR_LIST)
idx = contours[0].reshape(-1,2)
lidx = idx[:,0] + a.shape[1]*idx[:,1]
return np.unravel_index([lidx.min(), lidx.max()],a.shape)
请注意,对于3.0
之前的OpenCV版本,我们只会从cv2.findContours
获得两个输出。因此,对于这些版本,请跳过该步骤的_
。
让我们在给定的样本上使用它 -
In [188]: TL_LR(a,2)
Out[188]: (array([2, 7]), array([7, 8]))
In [189]: TL_LR(a,3)
Out[189]: (array([4, 8]), array([1, 4]))
In [190]: out # Output from previous approach
Out[190]:
array([[2, 7],
[7, 8],
[4, 1],
[8, 4]])