【问题标题】:Shape recognition with numpy/scipy (perhaps watershed)使用 numpy/scipy 进行形状识别(可能是分水岭)
【发布时间】:2012-03-13 17:39:45
【问题描述】:

我的目标是跟踪其中包含许多单独形状的绘图,并将这些形状拆分为单独的图像。它是白底黑字。我对 numpy,opencv&co 很陌生 - 但这是我目前的想法:

  • 扫描黑色像素
  • 找到黑色像素 -> 分水岭
  • 查找流域边界(作为多边形路径)
  • 继续搜索,但忽略已找到边界内的点

我不太擅长这些事情,有没有更好的方法?

首先我试图找到分水岭结果的矩形边界框(这或多或少是一个例子的拼贴):

from numpy import *
import numpy as np
from scipy import ndimage

np.set_printoptions(threshold=np.nan)

a = np.zeros((512, 512)).astype(np.uint8) #unsigned integer type needed by watershed
y, x = np.ogrid[0:512, 0:512]
m1 = ((y-200)**2 + (x-100)**2 < 30**2)
m2 = ((y-350)**2 + (x-400)**2 < 20**2)
m3 = ((y-260)**2 + (x-200)**2 < 20**2)
a[m1+m2+m3]=1

markers = np.zeros_like(a).astype(int16)
markers[0, 0] = 1
markers[200, 100] = 2
markers[350, 400] = 3
markers[260, 200] = 4

res = ndimage.watershed_ift(a.astype(uint8), markers)
unique(res) 

B = argwhere(res.astype(uint8))
(ystart, xstart), (ystop, xstop) = B.min(0), B.max(0) + 1 
tr = a[ystart:ystop, xstart:xstop]

print tr

不知何故,当我使用原始数组 (a) 时,argwhere 似乎可以工作,但在分水岭 (res) 之后它只是再次输出完整的数组。

下一步可能是找到形状周围的多边形路径,但现在边界框会很棒!

请帮忙!

【问题讨论】:

    标签: python numpy scipy watershed


    【解决方案1】:

    @Hooked 已经回答了你的大部分问题,但是当他回答时我正在写这个,所以我会发布它,希望它仍然有用......

    您正试图跳过太多的障碍。你不需要watershed_ift

    您使用scipy.ndimage.label 区分布尔数组中的单独对象,使用scipy.ndimage.find_objects 查找每个对象的边界框。

    让我们把事情分解一下。

    import numpy as np
    from scipy import ndimage
    import matplotlib.pyplot as plt
    
    def draw_circle(grid, x0, y0, radius):
        ny, nx = grid.shape
        y, x = np.ogrid[:ny, :nx]
        dist = np.hypot(x - x0, y - y0)
        grid[dist < radius] = True
        return grid
    
    # Generate 3 circles...
    a = np.zeros((512, 512), dtype=np.bool)
    draw_circle(a, 100, 200, 30)
    draw_circle(a, 400, 350, 20)
    draw_circle(a, 200, 260, 20)
    
    # Label the objects in the array. 
    labels, numobjects = ndimage.label(a)
    
    # Now find their bounding boxes (This will be a tuple of slice objects)
    # You can use each one to directly index your data. 
    # E.g. a[slices[0]] gives you the original data within the bounding box of the
    # first object.
    slices = ndimage.find_objects(labels)
    
    #-- Plotting... -------------------------------------
    fig, ax = plt.subplots()
    ax.imshow(a)
    ax.set_title('Original Data')
    
    fig, ax = plt.subplots()
    ax.imshow(labels)
    ax.set_title('Labeled objects')
    
    fig, axes = plt.subplots(ncols=numobjects)
    for ax, sli in zip(axes.flat, slices):
        ax.imshow(labels[sli], vmin=0, vmax=numobjects)
        tpl = 'BBox:\nymin:{0.start}, ymax:{0.stop}\nxmin:{1.start}, xmax:{1.stop}'
        ax.set_title(tpl.format(*sli))
    fig.suptitle('Individual Objects')
    
    plt.show()
    

    希望这样可以更清楚地了解如何找到对象的边界框。

    【讨论】:

    • 非常感谢你们的回答,我想就是这样。如果可以的话,只有一个新手 numpy 问题:我不能只保存边界矩形的区域,因为其他形状会“窥视”。所以我的计划是将图像区域乘以倒置的标签数组(这样当前形状之外的所有东西都变成黑色),然后用 ndimage 保存图像区域。你能指出我正确的方向吗?我知道,一有时间我会小心 rtfm!
    • 我想你只需要label == num,其中numlabel(标记数组)中的对象编号。诸如此类的操作是在 numpy 数组上进行矢量化的,因此实际上就是上面的语句。您将在“对象”内部得到一个布尔数组 True,在外部得到 False
    【解决方案2】:

    使用来自 scipy 的 ndimage 库。函数label 在阈值内的每个像素块上放置一个唯一标签。这标识了唯一的集群(形状)。从你对a的定义开始:

    from scipy import ndimage
    
    image_threshold = .5
    label_array, n_features =  ndimage.label(a>image_threshold)
    
    # Plot the resulting shapes
    import pylab as plt
    plt.subplot(121)
    plt.imshow(a)
    plt.subplot(122)
    plt.imshow(label_array)
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 2012-01-01
      • 2020-07-27
      • 2016-09-12
      • 2014-09-12
      • 1970-01-01
      • 1970-01-01
      • 2021-06-17
      • 2012-07-25
      相关资源
      最近更新 更多