Как сегментировать партию бобов для нейронной сети

У меня возникла проблема, когда я хочу идентифицировать разные кофейные зерна в смеси. Я создал нейронную сеть, которая способна идентифицировать разные бобы по отдельности. Но на практике я хочу разработать алгоритм, с помощью которого я смогу обнаруживать эти бобы в большей партии. Нет необходимости идентифицировать все бобы на картинке, но когда я могу идентифицировать 10-15 бобов в большей партии, этого будет достаточно.

Проблема теперь в том, что я могу сегментировать бобы, когда есть только один слой бобов с контрастным фоном, но когда под этим первым слоем есть несколько слоев бобов, это становится очень сложно.

Я попытался использовать преобразование расстояния и алгоритм водораздела из openCV, и, как уже упоминалось, это работало только для отдельных компонентов и для некоторого небольшого перекрытия между компонентами (как в этот пример). На рисунке ниже показаны результаты: результаты однослойной сегментации

Мой используемый код был основан на приведенном выше примере:

import cv2 
import numpy as np
from matplotlib import pyplot as plt
from scipy.ndimage import label
from scipy.ndimage import morphology

# load the image as normal and grayscale 
img_path = "FINAL/segmentation/IMG_6699.JPG"
img= cv.imread(img_path,0)
img0 = cv.imread(img_path)

#preprocess the image
img= cv.medianBlur(img,5)
ret,th1 = cv.threshold(img,80,255,cv.THRESH_BINARY_INV)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(th1, cv2.MORPH_OPEN, kernel)
dilation = cv2.dilate(opening, None, iterations=2)
erosion = cv2.erode(dilation,kernel,iterations = 50)
border_nonseg = dilation - cv2.erode(dilation, None, iterations = 1)


#distance transform 
#dt = morphology.distance_transform_bf(dilation, metric='chessboard')
dt = cv2.distanceTransform(dilation, 2, 5)   
dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(np.uint8)
hier, dt1 = cv2.threshold(dt, 170, 255, cv2.THRESH_BINARY)

# label the centers found by the distance transform 
lbl, ncc = label(dt1)
lbl = lbl * (255/ncc)      
# Completing the markers now. 
lbl[border_nonseg == 255] = 255
lbl = lbl.astype(np.int32)

# Watershed algorithm 
cv2.watershed(img0, lbl)

lbl[lbl == -1] = 0
lbl = lbl.astype(np.uint8)
result = 255 - lbl
lbl_cont = result

# Draw the borders 
result[result != 255] = 0
result = cv2.dilate(result, None, iterations=1)
img0[result == 255] = (255, 0, 0)
cv2.imwrite("output.png", img0)
contours, _ = cv.findContours(result, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

titles = ['Original Image', 'dilation',
            'gradient morph', 'erode']
images = [ border_nonseg, dt, lbl_cont, img0]
plt.figure(figsize=(20,20))
for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

Но проблема начинается, когда появляется такая картина (что является реальной ситуацией): многослойная сегментация и более жесткая многоуровневая сегментация

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

Мне очень интересно услышать разные мнения по этому поводу!


person JelmerTH    schedule 29.03.2021    source источник
comment
Добро пожаловать в Stackoverflow. Насколько я понимаю ваш вопрос, код не выдает никаких ошибок. Вместо этого он работает не так хорошо, как вы ожидаете. Если это так, я предлагаю вам прочитать об алгоритмах сегментации изображений. Если у вас есть большой размеченный набор данных, вы можете попробовать машинное обучение.   -  person Molitoris    schedule 29.03.2021
comment
@Molitoris спасибо за ваш ответ. Действительно, код работает корректно для красиво расположенных бинов, но не для множества несортированных слоев бинов. Я пробовал все разные настройки с текущим кодом, но пока безуспешно. Вот почему я думал, что будут разные подходы, о которых я не знал. Я пробовал уже большинство задач контролируемой сегментации от scikit. К сожалению, нет времени (читай: стоит вложений) аннотировать 1000 фотографий, чтобы использовать машинное обучение для автоматической сегментации.   -  person JelmerTH    schedule 29.03.2021
comment
Насколько я понимаю, вы пробовали множество традиционных алгоритмов сегментации изображений. Я не уверен, что смогу помочь вам в этом направлении. Вы думали о трансферном обучении. Существует множество предварительно обученных моделей для сегментации изображений. Они, вероятно, не были обучены на бобах. Однако небольшого набора изображений сегментированных бобов может быть достаточно, чтобы обучить одну из этих моделей для решения вашей задачи.   -  person Molitoris    schedule 29.03.2021
comment
Идентифицируете ли вы какой-либо bean-компонент при передаче изображений, которые трудно сегментировать, в вашу NN? вы тренируете NN с такими сложными изображениями? Какую архитектуру NN вы используете? под присмотром или без присмотра?   -  person Amo Robb    schedule 15.04.2021
comment
@AmoRobb Спасибо за ваш ответ. Я обучил свою NN отдельным bean-компонентам, что в данном случае не является проблемой. Я использовал бобы на первой картинке в качестве метода сбора данных. рисуя и разрезая ограничивающие рамки вокруг компонента и используя их в качестве данных для моей NN. Проблема в том, что я хочу сделать это и на изображениях, которые сложнее сегментировать. Также есть возможность обрезать изображение так, чтобы в нем поместился один боб. Но сегментация по-прежнему остается проблемой...   -  person JelmerTH    schedule 21.04.2021


Ответы (1)


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

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

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

Другой подход заключается в использовании некоторого более общего распознавания образов:

а) На основе формы: они пытаются сопоставить контурную модель с градиентным изображением.

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

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

Вы также можете попробовать c) метод расширения области, который расширяет исходную область до соседних пикселей при некоторых условиях, основанных на гладкости цвета, или d) поиск границы в сочетании с некоторыми алгоритмами закрытия контура. ; но я боюсь, что они могут вызвать у вас много проблем из-за изменчивости ваших изображений.

person Amo Robb    schedule 21.04.2021