Python 使用numpy/scipy进行形状识别(可能是分水岭)

Python 使用numpy/scipy进行形状识别(可能是分水岭),python,numpy,scipy,watershed,Python,Numpy,Scipy,Watershed,我的目标是跟踪那些有很多单独形状的图形,并将这些形状分割成单独的图像。它是黑白相间的。我对numpy、opencv&co是个新手,但我现在的想法是: 扫描黑色像素 发现黑色像素->分水岭 查找流域边界(作为多边形路径) 继续搜索,但忽略已找到边界内的点 我不太擅长这类事情,有没有更好的办法 首先,我试图找到分水岭结果的矩形边界框(这或多或少是一个拼贴示例): 从numpy导入* 将numpy作为np导入 从scipy导入ndimage np.set\u打印选项(阈值=np.nan) a=np

我的目标是跟踪那些有很多单独形状的图形,并将这些形状分割成单独的图像。它是黑白相间的。我对numpy、opencv&co是个新手,但我现在的想法是:

  • 扫描黑色像素
  • 发现黑色像素->分水岭
  • 查找流域边界(作为多边形路径)
  • 继续搜索,但忽略已找到边界内的点
我不太擅长这类事情,有没有更好的办法

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

从numpy导入*
将numpy作为np导入
从scipy导入ndimage
np.set\u打印选项(阈值=np.nan)
a=np.zeros((512,512)).astype(np.uint8)#分水岭所需的无符号整数类型
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.zero_like(a).aType(int16)
标记[0,0]=1
标记[200100]=2
标记[350400]=3
标记[260200]=4
res=ndimage.divident\u ift(a.astype(uint8),标记)
独特的(res)
B=argwhere(res.astype(uint8))
(ystart,xstart),(ystop,xstop)=B.min(0),B.max(0)+1
tr=a[ystart:ystop,xstart:xstop]
打印tr

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

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


请帮忙

使用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()

虽然他已经回答了你的大部分问题,但当他回答时,我正在写这篇文章,所以我会寄希望于它仍然有用…… 你想跳过太多的障碍。您不需要
分水岭\u if

您可以使用
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导入为np
从scipy导入ndimage
将matplotlib.pyplot作为plt导入
def绘制圆(网格,x0,y0,半径):
ny,nx=grid.shape
y、 x=np.ogrid[:ny,:nx]
dist=np.hypot(x-x0,y-y0)
网格[距离<半径]=真
回流栅
#生成3个圆。。。
a=np.zero((512,512),dtype=np.bool)
画圆(a,100,200,30)
画圆(a,400,350,20)
画圆(a,200,260,20)
#为阵列中的对象添加标签。
标签,numobjects=ndimage.label(a)
#现在找到它们的边界框(这将是切片对象的元组)
#您可以使用每一个直接索引数据。
#例如,[slices[0]]为您提供了该对象边界框内的原始数据
#第一个目标。
切片=nImage.find_对象(标签)
#--绘图-------------------------------------
图,ax=plt.子批次()
ax.imshow(a)
ax.集合标题(“原始数据”)
图,ax=plt.子批次()
ax.imshow(标签)
ax.set_title(“标记对象”)
图,轴=plt子批次(ncols=多个项目)
对于ax,拉链中的sli(axes.flat,切片):
imshow(标签[sli],vmin=0,vmax=numobjects)
tpl='BBox:\nymin:{0.start},ymax:{0.stop}\nxmin:{1.start},xmax:{1.stop}'
ax.集合标题(tpl.格式(*sli))
图suptitle(“单个对象”)
plt.show()


希望这能让我们更清楚地找到对象的边界框。

非常感谢你们两位的回答,我想就是这个了。如果可以的话,我只能问一个新手的问题:我不能只保存边界矩形的区域,因为其他形状将“窥视”。因此,我的计划是将图像区域乘以反转标签数组(使当前形状之外的所有内容都变为黑色),然后用ndimage保存图像区域。你能告诉我正确的方向怎么做吗?我知道,只要我有时间我会认真的rtfm!我想您只需要
label==num
其中
num
label
中对象的编号(带标签的数组)。像这样的操作是在numpy数组上矢量化的,所以它就是上面的语句。您将在“对象”内部得到一个布尔数组
True
,在外部得到
False
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()