Использование regionprops в Python

Я пытаюсь проанализировать стеки TIFF в оттенках серого, в которых данный кадр будет выглядеть как это. Я фильтрую его (используя размытие по Гауссу), а затем преобразовываю в двоичную форму (используя метод Оцу для определения порога).

Код MATLAB, который отлично работает:

image_conncomp = bwconncomp(image_binary); # entire stack is held in image_binary

for i=1:image_conncomp.NumObjects
    object_size = length(image_conncomp.PixelIdxList{i});
end

Каждое белое пятно на изображении в качестве примера получено, и его объем (в пикселях) довольно точно передан object_size.

Код Python:

from skimage import measure

labels = measure.label(image_binary, background=1) # same image_binary as above
propsa = measure.regionprops(labels)

for label in propsa:
    object_size = len(label.coords)

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

Что эти функции делают по-другому? Я был бы счастлив попробовать другой подход в Python для вычисления размеров объектов, но я изо всех сил пытался найти другой. Было бы здорово иметь версию этого кода для Python, если бы я мог найти хорошую замену функции Matlab bwconncomp.

Использование regionprops в Python

А вывод measure.label смотрели?

Cris Luengo 09.07.2018 18:19

Я, честно говоря, не понимаю вывод в исходном виде. Он должен маркировать объекты, которые он распознает, но не уверен, как именно он это делает.

oofin 09.07.2018 18:41

Почему вы установили background = 1? Конечно, это не по умолчанию в Matlab? Кроме того, у объектов RegionProp есть несколько хороших свойств, в том числе желаемая область: for prop in propsa: object_size = prop.area. В любом случае, я предлагаю использовать skimage.color.label2rgb, чтобы посмотреть на изображение метки и убедиться, что этот шаг работает. Остальное выглядит хорошо (при условии, что двоичные файлы действительно идентичны, и что фон установлен на 0, я думаю)

Juan 10.07.2018 06:27
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
10 364
2

Ответы 2

Что-то вроде этого?

from skimage.io import imread, imshow
from skimage.filters import gaussian, threshold_otsu
from skimage import measure
import matplotlib.pyplot as plt

original = imread('https://i.stack.imgur.com/nkQpj.png')
blurred = gaussian(original, sigma=.8)
binary = blurred > threshold_otsu(blurred)
labels = measure.label(binary)

plots = {'Original': original, 'Blurred': blurred, 
         'Binary': binary, 'Labels': labels}
fig, ax = plt.subplots(1, len(plots))
for n, (title, img) in enumerate(plots.items()):
    cmap = plt.cm.gnuplot if n == len(plots) - 1 else plt.cm.gray
    ax[n].imshow(img, cmap=cmap)
    ax[n].axis('off')
    ax[n].set_title(title)
plt.show(fig)

props = measure.regionprops(labels)
for prop in props:
    print('Label: {} >> Object size: {}'.format(prop.label, prop.area))

Выход:

Plots

Label: 1 >> Object size: 37
Label: 2 >> Object size: 66
Label: 3 >> Object size: 1

Это отлично подходит для измерения площади. Однако я ищу объем. Как правило, в стеке будет 34 кадра, как в образце изображения выше. Объекты будут отображаться более чем в одном кадре, но не во всех, поэтому я должен смотреть на весь стек одновременно, чтобы действительно получить объем. Чтобы измерить объем, я просто хочу посчитать количество пикселей, обнаруженных в объекте.

oofin 21.07.2018 19:25

В этом случае вам нужно перебрать стек и вычислить объем как сумму площадей областей, которые соответствуют одному и тому же объекту.

Tonechas 21.07.2018 19:47

но как я узнаю, что это один и тот же объект? единственный метод, который я могу придумать, - это вычислить расстояние между центроидами, но это звучит очень дорого.

oofin 21.07.2018 20:10

Я добавил стек (преобразованный в png, Chrome не может отображать .tiff) в конец исходного вопроса

oofin 21.07.2018 22:06

Я не могу загрузить стек по указанному вами URL. Не могли бы вы опубликовать ссылку на Dropbox / Google Диск?

Tonechas 21.07.2018 23:51

Я пропустил это обсуждение. @oofin, свойство area фактически возвращает объем, если ваше изображение трехмерное.

Juan 02.02.2019 05:53

Мы могли бы сделать то же самое, сначала применив морфологическое закрытие scipy.ndimage к пороговому двоичному изображению, а затем функцию label(), чтобы объединить связанные области в двоичном изображении, как показано ниже (размер областей немного отличается и будет зависеть от размера морфологического ядра):

from scipy.ndimage import label
from scipy.ndimage.morphology import binary_closing
from skimage.filters import threshold_otsu
import matplotlib.pylab as plt

original = plt.imread('https://i.stack.imgur.com/nkQpj.png')
thres = threshold_otsu(original)
binary = original > thres
binary_closed = binary_closing(binary, structure=np.ones((2,2)))
labeled_image, num_features = label(binary_closed)
feature_areas = np.bincount(labeled_image.ravel())[1:]   
print(feature_areas) # if we use 3x3 SE we shall get two regions with areas 24, 46
# [24 42  1]

plt.figure(figsize=(8,7))
plt.gray()
plt.subplot(221), plt.imshow(original), plt.axis('off'), plt.title('original')
plt.subplot(222), plt.imshow(binary), plt.axis('off'), plt.title('binray')
plt.subplot(223), plt.imshow(binary_closed), plt.axis('off'), plt.title('binray closed')
plt.subplot(224), plt.imshow(labeled_image, cmap='inferno'), plt.axis('off'), plt.title('labelled')
plt.show()

чтобы получить следующий результат:

Другие вопросы по теме