在python,opencv2,numpy

时间:2016-11-22 14:04:36

标签: python opencv numpy scipy

我正在尝试提取图像蒙版的两个区域的索引/位置,我正在使用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. 最左边的区域 - 下面标记为(n)
  2. 最右边的区域 - 下面标有[n]
  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这样的问题吗?

1 个答案:

答案 0 :(得分:1)

基于NumPy的解决方案

在输入图像数组的展平版本上,topmost leftmost位置将是第一个,而lowermost rightmost将是最后一个。因此,一个技巧是使用np.nonzero获得这两个区域的扁平索引,并简单地查找minmax索引以分别获得这些预期输出。最后,我们将使用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 leftmostlowermost 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]])