2016-07-26 8 views
3

いくつかの不規則なオブジェクトが含まれている画像があれば、その個々の直径を探したいと思います。Pythonで画像処理を使用してオブジェクトの直径を見つける方法は?

Thanks to this answer私はオブジェクトを識別する方法を知っています。 しかし、画像に表示されているオブジェクトの最大直径を測定することは可能ですか?

私はscipy-ndimageのマニュアルを調べており、専用の機能が見つかりませんでした。オブジェクト識別のための

コード:

import numpy as np 
from scipy import ndimage 
from matplotlib import pyplot as plt 

# generate some lowpass-filtered noise as a test image 
gen = np.random.RandomState(0) 
img = gen.poisson(2, size=(512, 512)) 
img = ndimage.gaussian_filter(img.astype(np.double), (30, 30)) 
img -= img.min() 
img /= img.max() 

# use a boolean condition to find where pixel values are > 0.75 
blobs = img > 0.75 

# label connected regions that satisfy this condition 
labels, nlabels = ndimage.label(blobs) 

# find their centres of mass. in this case I'm weighting by the pixel values in 
# `img`, but you could also pass the boolean values in `blobs` to compute the 
# unweighted centroids. 
r, c = np.vstack(ndimage.center_of_mass(img, labels, np.arange(nlabels) + 1)).T 

# find their distances from the top-left corner 
d = np.sqrt(r*r + c*c) 

# plot 
fig, ax = plt.subplots(1, 2, sharex=True, sharey=True, figsize=(10, 5)) 
ax[0].imshow(img) 
ax[1].hold(True) 
ax[1].imshow(np.ma.masked_array(labels, ~blobs), cmap=plt.cm.rainbow) 
for ri, ci, di in zip(r, c, d): 
    ax[1].annotate('', xy=(0, 0), xytext=(ci, ri), 
        arrowprops={'arrowstyle':'<-', 'shrinkA':0}) 
    ax[1].annotate('d=%.1f' % di, xy=(ci, ri), xytext=(0, -5), 
        textcoords='offset points', ha='center', va='top', 
        fontsize='x-large') 
for aa in ax.flat: 
    aa.set_axis_off() 
fig.tight_layout() 
plt.show() 

画像: enter image description here

+1

一般的にはそれほど問題にはなりません。 OpenCV(これはPythonのバインディングを持っています)には 'minEnclosingCircle'がありますが、ndimageには何か似ていません。たとえば、https://en.wikipedia.org/wiki/Smallest-circle_problem – tom10

答えて

5

あなたのイメージ内のすべての領域のバウンディングボックスを決定するためにskimage.measure.regionpropsを使用することができます。大体円形のブロブの場合、最小包囲円の直径は、の最大辺によって近似することができる。そうするためにあなたは自分のスクリプトの末尾に次のコードを追加する必要があります。

from skimage.measure import regionprops 

properties = regionprops(labels) 
print 'Label \tLargest side' 
for p in properties: 
    min_row, min_col, max_row, max_col = p.bbox 
    print '%5d %14.3f' % (p.label, max(max_row - min_row, max_col - min_col)) 

fig = plt.figure() 
ax = fig.add_subplot(111)  
ax.imshow(np.ma.masked_array(labels, ~blobs), cmap=plt.cm.gist_rainbow) 
ax.set_title('Labeled objects') 
plt.xticks([]) 
plt.yticks([]) 
for ri, ci, li in zip(r, c, range(1, nlabels+1)): 
    ax.annotate(li, xy=(ci, ri), fontsize=24) 
plt.show() 

そして、これはあなたが得る出力されます:

Label Largest side 
    1  106.000 
    2   75.000 
    3   79.000 
    4   56.000 
    5  161.000 
    6   35.000 
    7   47.000 

Labeled objects

+0

なども参照してください。理解を深めるためのカップルの発言。 1)「N」または「ビン」をイメージ内のオブジェクトの数と解釈できますか?もしそうなら、 'N = nlabels'ですか? 2)細胞の数に関して「最大の側面」を解釈するのは正しいですか? – FaCoffee

+0

1)私は自分の答えを簡略化し、「N」はもう使われなくなりました。 2)最大辺はピクセル単位で測定されます。 – Tonechas

1

私が使用して提案します距離変換。だからあなたはあなたがあなたのラベルイメージを持ったら:

dt = ndimage.distance_transform_edt(blobs) 
slices = ndimage.find_objects(input=labels) 
radii = [np.amax(dt[s]) for s in slices] 

これは、(3Dまたは球)最大内接円を提供します。 find_objects関数は非常に便利です。 Python スライスオブジェクトのリストを返します。このオブジェクトを使用して、ブロブを含む特定の場所のイメージにインデックスを付けることができます。もちろん、これらのスライスを使用して距離変換画像にインデックスを付けることができます。したがって、スライス内の距離変換の最大値は、あなたが探している半径です。

上記のコードには1つの潜在的なゴチチャがあります。スライスは正方形(または立方体)のセクションなので、互いに接近している場合は小さな小片が含まれている可能性があります。

radii = [np.amax(dt[slices[i]]*(labels[slices[i]] == (i+1))) for i in range(nlabels)] 

距離はスライスでインデックス化されることになっているブロブに変換リスト内包マスクの上のバージョンは、それによって不要な干渉を取り除く:以下のように、もう少し複雑なロジックでこの問題を回避することができます隣接するブロブから。

関連する問題