Автоматически находить мелкие объекты на изображении и извлекать их как изображения меньшего размера.

Мы планируем создавать фотографии мелких частиц с помощью микроскопа. Эти мелкие элементы имеют тенденцию быть выпуклыми и не должны соприкасаться друг с другом. Фон может быть немного зашумлен, но между фоном и элементами должен быть большой контраст (мы стремимся создавать изображения, как в примере). Я хотел бы извлечь все отдельные элементы, обрезать их и сохранить как отдельные изображения. Мне нужен инструмент, способный решить эту проблему и в тех случаях, когда граница между элементом и фоном менее определена.

После того, как я извлек все фотографии, я запускаю сценарий Matlab для каждого изображения.

Операционная система: желательно Linux, но можно и Windows.

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

Образец изображения:

Вы будете выбирать вручную? Или инструмент должен каким-то образом угадывать, что вы считаете «отдельным элементом»? Какая операционная система?
Всегда ли будет однотонный монохромный фон? Могут ли объекты пересекаться? Может быть, если вы расскажете нам, как вы планируете его использовать? Здесь очень мало информации, на которой можно основывать помощь.
Эта проблема начинается легко, но становится очень сложной по мере того, как добавляется сложность (например, занятые фоны), и, вероятно, не существует ранее существовавшего упрощенного решения даже для простых случаев. Однако вы, вероятно, могли бы продвинуться довольно далеко с помощью простого алгоритма, реализованного примерно в 30 строках Python.

Ответы (1)

Вот программа Python 3, которая отличает пиксели объекта от пикселя, не являющегося объектом, просто устанавливая порог красного канала на 128.

import sys
from PIL import Image

orig = Image.open(sys.argv[1])
width = orig.width
height = orig.height

# The workspace will be a list of lists of bools, where True
# means an object pixel.
workspace = list(orig.getdata())
workspace = list(zip(*(workspace[i * width : (i + 1) * width] for i in range(height))))
workspace = [[r < 128 for r, _, _ in col] for col in workspace]

n_objects = 0

for x in range(width):
    for y in range(height):
        if workspace[x][y]:
            n_objects += 1
            # Start a bounding box at this pixel.
            x1, x2, y1, y2 = x, x, y, y
            # Try growing the bounding box in each direction,
            # one pixel at a time, until none of the four
            # directions will get us another object pixel.
            while True:
                if   x1 > 0          and any(workspace[x1 - 1][yt    ] for yt in range(y1, y2 + 1)):  x1 -= 1
                elif x2 < width  - 1 and any(workspace[x2 + 1][yt    ] for yt in range(y1, y2 + 1)):  x2 += 1
                elif y1 > 0          and any(workspace[xt    ][y1 - 1] for xt in range(x1, x2 + 1)):  y1 -= 1
                elif y2 < height - 1 and any(workspace[xt    ][y2 + 1] for xt in range(x1, x2 + 1)):  y2 += 1
                else: break
            # Save everything in the bounding box as a new image.
            orig.crop((x1, y1, x2, y2)).save("out/obj-{:04d}-{:04d}.png".format(x1, y1))
            # Clear the workspace here so we don't re-process this object.
            for xt in range(x1, x2 + 1):
                for yt in range(y1, y2 + 1):
                    workspace[xt][yt] = False

print("Extracted", n_objects, "objects.")

Вот как выглядят полученные файлы (не показаны в одинаковом масштабе):

Объекты как отдельные изображения