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' или' bins' интерпретироваться как количество объектов на изображении? Если это так, '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 , которые можно использовать для индексирования изображения в определенных местах, содержащих капли. Разумеется, эти срезы могут быть использованы для индексации изображения расстояния. Таким образом, наибольшее значение преобразования расстояния внутри среза - это радиус, который вы ищете.

Существует один потенциальный gothcha из приведенного выше кода: срез представляет собой квадратную (или кубическую) секцию, поэтому они могут содержать небольшие кусочки других капель, если они близки друг к другу. Вы можете обойти эту проблему с немного более сложной логикой следующим образом:

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

выше версия списка понимания масок расстояния преобразования с сгустком, который должен быть проиндексирован срезом, тем самым удаляя любые нежелательные помехи из соседних капель.

 Смежные вопросы

  • Нет связанных вопросов^_^