#matlab #opencv #image-processing #image-segmentation #scikit-image
#matlab #opencv #обработка изображений #изображение-сегментация #scikit-изображение
Вопрос:
Я пытался отделить человеческое тело на изображении от фона, но все методы, которые я видел, похоже, не очень хорошо работают для меня.
Я собрал следующие изображения;
Теперь я хочу вырезать человека из фона. Я попытался вычесть изображение фона из изображения с помощью res = cv2.subtract(background, foreground)
пользователя (я новичок в обработке изображений).
Методы вычитания фона в opencv, подобные cv2.BackgroundSubtractorMOG2()
и cv2.BackgroundSubtractorMOG2()
работающие только с видео или последовательностью изображений, и методы определения контуров, которые я видел, предназначены только для сплошных фигур.
И GrabCut не совсем хорошо работает для меня, потому что я хотел бы автоматизировать процесс.
Учитывая имеющиеся у меня изображения (изображение фона и изображение фона с человеком в нем), есть ли способ вырезать человека из фона?
Комментарии:
1. пожалуйста, разместите фотографии и исходный код, иллюстрирующие вашу проблему
2. Привет @ChristophRackwitz Я добавил изображения к вопросу
3. Можете ли вы отключить какие-либо автоматические настройки на камере? Автоматический баланс белого, в частности, затрудняет выполнение простых методов вычитания, поскольку он изменяет фактические цвета объектов, когда вы попадаете в поле зрения на втором снимке.
Ответ №1:
Я бы не рекомендовал нейронную сеть для этой проблемы. Это большая работа для чего-то подобного, когда у вас есть известный фон. Я пройдусь по шагам, которые я предпринял, чтобы выполнить сегментацию фона на этом изображении.
Сначала я перешел в цветовое пространство ЛАБОРАТОРИИ, чтобы получить несколько светостойких каналов для работы. Я выполнил простое вычитание переднего плана и фона и объединил каналы a и b.
Вы можете видеть, что на заднем плане все еще происходит значительное изменение цвета даже при использовании менее чувствительного к свету цветового канала. Вероятно, это связано с автоматическим балансом белого на камере, вы можете видеть, что некоторые цвета фона меняются, когда вы попадаете в поле зрения.
Следующим шагом, который я предпринял, было установление порога для этого изображения. Оптимальные пороговые значения не всегда могут быть одинаковыми, вам придется настроить диапазон, который хорошо подходит для вашего набора фотографий.
Я использовал функцию findContours OpenCV для получения точек сегментации каждого большого двоичного объекта и отфильтровал доступные контуры по размеру. Я установил пороговое значение размера 15000. Для справки, у человека на изображении была пиксельная область 27551.
Тогда это просто вопрос обрезки контура.
Этот метод работает для любой хорошей стратегии определения порога. Если вы можете улучшить согласованность своих изображений, отключив автоматические настройки и обеспечив хороший контраст человека на фоне стены, вы можете использовать более простые стратегии определения порога и получить хорошие результаты.
Просто для удовольствия:
Редактировать:
Я забыл добавить код, который я использовал:
import cv2
import numpy as np
# rescale values
def rescale(img, orig, new):
img = np.divide(img, orig);
img = np.multiply(img, new);
img = img.astype(np.uint8);
return img;
# get abs(diff) of all hue values
def diff(bg, fg):
# do both sides
lh = bg - fg;
rh = fg - bg;
# pick minimum # this works because of uint wrapping
low = np.minimum(lh, rh);
return low;
# load image
bg = cv2.imread("back.jpg");
fg = cv2.imread("person.jpg");
fg_original = fg.copy();
# blur
bg = cv2.blur(bg,(5,5));
fg = cv2.blur(fg,(5,5));
# convert to lab
bg_lab = cv2.cvtColor(bg, cv2.COLOR_BGR2LAB);
fg_lab = cv2.cvtColor(fg, cv2.COLOR_BGR2LAB);
bl, ba, bb = cv2.split(bg_lab);
fl, fa, fb = cv2.split(fg_lab);
# subtract
d_b = diff(bb, fb);
d_a = diff(ba, fa);
# rescale for contrast
d_b = rescale(d_b, np.max(d_b), 255);
d_a = rescale(d_a, np.max(d_a), 255);
# combine
combined = np.maximum(d_b, d_a);
# threshold
# check your threshold range, this will work for
# this image, but may not work for others
# in general: having a strong contrast with the wall makes this easier
thresh = cv2.inRange(combined, 70, 255);
# opening and closing
kernel = np.ones((3,3), np.uint8);
# closing
thresh = cv2.dilate(thresh, kernel, iterations = 2);
thresh = cv2.erode(thresh, kernel, iterations = 2);
# opening
thresh = cv2.erode(thresh, kernel, iterations = 2);
thresh = cv2.dilate(thresh, kernel, iterations = 3);
# contours
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# filter contours by size
big_cntrs = [];
marked = fg_original.copy();
for contour in contours:
area = cv2.contourArea(contour);
if area > 15000:
print(area);
big_cntrs.append(contour);
cv2.drawContours(marked, big_cntrs, -1, (0, 255, 0), 3);
# create a mask of the contoured image
mask = np.zeros_like(fb);
mask = cv2.drawContours(mask, big_cntrs, -1, 255, -1);
# erode mask slightly (boundary pixels on wall get color shifted)
mask = cv2.erode(mask, kernel, iterations = 1);
# crop out
out = np.zeros_like(fg_original) # Extract out the object and place into output image
out[mask == 255] = fg_original[mask == 255];
# show
cv2.imshow("combined", combined);
cv2.imshow("thresh", thresh);
cv2.imshow("marked", marked);
# cv2.imshow("masked", mask);
cv2.imshow("out", out);
cv2.waitKey(0);
Ответ №2:
Поскольку очень легко найти набор данных, состоящий из большого количества человеческого тела, я предлагаю вам реализовать методы сегментации нейронной сети для идеального извлечения человеческого тела. Пожалуйста, проверьте эту ссылку, чтобы увидеть аналогичный пример.
Комментарии:
1. Спасибо @Enes Uguroglu за ответ, я бы проверил это.