Цель
В этой главе,
- Мы увидим алгоритм GrabCut для извлечения переднего плана в изображении.
- Для этого мы создадим интерактивное приложение.
теория
Алгоритм GrabCut был разработан Карстеном Ротером, Владимиром Колмогоровым и Эндрю Блейком из Microsoft Research UK. В своей статье «GrabCut»: Интерактивное извлечение переднего плана с использованием итеративных сокращений графа. Алгоритмы, которые требуют извлечения переднего плана с минимальным вмешательством пользователя, приводят к GrabCut.
Как это работает с точки зрения пользователя? Сначала пользователь рисует прямоугольник вокруг области переднего плана (область переднего плана должна полностью находиться внутри прямоугольника). Затем алгоритм итеративно делит его, чтобы получить наилучший результат. Выполнено, но в некоторых случаях сегментация может быть не очень хорошей, например, некоторые области переднего плана могут быть отмечены как фон и наоборот. В этом случае требуется доработка пользователем. Просто нарисуйте несколько штрихов на неправильно сегментированных участках изображения. Обводка в основном говорит: «Эй, эта область должна быть на переднем плане, вы отмечаете ее как фон, исправляете ее в следующей итерации» или наоборот. Тогда в следующей итерации вы получите лучшие результаты.
См. изображение ниже. Первый игрок и футбольный мяч заключены в синий прямоугольник. Затем сделайте последние штрихи белыми штрихами (для переднего плана) и черными штрихами (для фона). И мы получили хорошие результаты.
Так что же произошло на заднем плане?
- Прямоугольник пользовательского ввода. Все, что находится за пределами этого прямоугольника, будет фоном (по этой причине прямоугольник должен содержать все объекты). Все внутри прямоугольника неизвестно. Кроме того, любой пользовательский ввод, определяющий передний план и фон, обрабатывается как жестко помеченный, что означает, что они не меняются в процессе.
- Компьютер делает первоначальную оценку на основании предоставленных нами данных. Он помечает пиксели переднего плана и фона (или жестко помечает их), которые теперь моделируются с использованием модели смеси Гаусса (GMM).
- На основе предоставленных нами данных GMM может изучать и создавать новые распределения пикселей. То есть неизвестные пиксели помечаются как возможные передний план или возможный фон (точно так же, как кластеры) в зависимости от того, как их цвета статистически связаны с другими жестко помеченными пикселями.
- Постройте график из этого распределения пикселей. Узлы на графике — это пиксели. Были добавлены еще два узла: узел «источник» и узел «приемник». Каждый пиксель переднего плана подключен к исходному узлу, а каждый фоновый пиксель подключен к узлу-приемнику.
- Веса ребер, соединяющих пиксели с исходными/конечными узлами, определяются вероятностью того, что пиксель находится на переднем плане/фоне. Веса между пикселями определяются информацией о краях или сходством пикселей. Если цвета пикселей сильно различаются, границы между ними будут низкими.
- Затем граф сегментируется с использованием алгоритма mincut. Он разрезает граф на два отдельных узла-источника и приемника с наименьшей функцией стоимости. Функция стоимости представляет собой сумму всех весов отрезанных ребер. После отсечения все пиксели, подключенные к узлу «Источник», становятся передним планом, а пиксели, подключенные к узлу «Приемник», становятся фоном.
- Продолжайте этот процесс, пока классификация не сойдется.
Как показано на рисунке ниже (рисунок предоставлен: http://www.cs.ru.ac.za/research/g02m1682/)
Пример
Теперь мы используем OpenCV для алгоритма захвата. OpenCV имеет функции для этогоcv.grabCut(), мы сначала увидим его параметры:
- img- входное изображение
-
mask- Это изображение-маска, в котором мы указываем, какие области являются фоном, передним планом или, возможно, фоном/передним планом и т. д. Это делается с помощью следующих флагов:cv.GC_BGD,cv.GC_FGD, cv.GCPRBGD,cv.GCPRFGD, или напрямую
0,1,2,3
переходил на образ. -
rect- это координаты прямоугольника, в который входит объект переднего плана, в формате
(x,y,w,h)
-
bdgModel, fgdModel- Это массивы, используемые внутри алгоритма. Вы просто создаете два размера
(1,65)
изnp.float64
Массив нулевого типа. - iterCount- Количество итераций, которые должен выполнить алгоритм.
- model- должно бытьcv.GCINITWITH_RECTилиcv.GCINITWITH_MASKИли комбинацию из двух, решите, хотим ли мы нарисовать прямоугольник или окончательный косметический штрих.
Сначала давайте посмотрим на режим прямоугольника. Мы загружаем изображение, создавая аналогичное изображение маски. мы создаемfgdModelиbgdModel. Задаем параметры прямоугольника. Все прямо вперед. Пусть алгоритм работает в течение 5 итераций. режим должен бытьcv.GCINITWITH_RECT, так как мы используем прямоугольник. Затем запустите Grabcut. Измените изображение маски. В новом изображении маски пиксели будут отмечены четырьмя маркерами, представляющими фон/передний план, указанные выше. Поэтому мы модифицируем маску так, чтобы все пиксели 0 и 2 были установлены в 0 (т.е. фон), а все пиксели 1 и 3 были установлены в 1 (т.е. пиксели переднего плана). Вот и готова наша последняя маска. Просто умножьте его на входное изображение, чтобы получить сегментированное изображение.
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg')
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (50,50,450,290)
cv.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
Проверьте результаты ниже:
Упс, волосы Мэйси пропали. Кто бы полюбил Месси без волос? Нам нужно вернуть его. Поэтому мы будем использовать 1 пиксель (для переднего плана) для тонкой ретуши. В то же время на снимке появился нежелательный фон. Нам нужно их удалить. Там мы даем ретушь 0px (чтобы убедиться, что фон). Итак, как сказано сейчас, мы модифицируем сгенерированную маску в предыдущем случае.
Что я на самом деле сделал, так это то, что я открыл входное изображение в приложении для рисования и добавил к изображению еще один слой. Используя инструмент «кисть» в кисти, я отметил белым цветом пропущенный передний план (волосы, обувь, мяч и т. д.) на новом слое, а нежелательный фон (например, логотип, землю и т. д.) — белым. Затем залейте оставшийся фон серым цветом. Затем загрузите это изображение маски в OpenCV, отредактируйте исходное изображение маски с соответствующими значениями во вновь добавленном изображении маски.
Проверьте следующий код:
#newmask是我手动标记过的mask图像
newmask = cv.imread('newmask.png',0)
# 标记为白色(确保前景)的地方,更改mask = 1
# 标记为黑色(确保背景)的地方,更改mask = 0
mask[newmask == 0] = 0
mask[newmask == 255] = 1
mask, bgdModel, fgdModel = cv.grabCut(img,mask,None,bgdModel,fgdModel,5,cv.GC_INIT_WITH_MASK)
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
Проверьте результаты ниже:
Вот и все. Здесь вместо инициализации непосредственно в прямоугольном режиме вы можете напрямую войти в режим маски. Просто отметьте прямоугольную область на изображении маски размером 2px или 3px (возможный фон/передний план). Затем отметьте наш sure_foreground как 1 пиксель, как во втором примере. Затем непосредственно примените функцию захватаCut в режиме маски.
Упражнение
- Примеры OpenCV включают в себя пример catchcut.py, интерактивный инструмент, который использует захват. Проверять. Также посмотрите видео на YouTube о том, как его использовать.
- Здесь вы можете сделать его интерактивным примером, нарисовав прямоугольники и используя штрихи мыши, создав полосу отслеживания для регулировки ширины штриха и многое другое.
Сводная станция блога о технологиях искусственного интеллекта Panchuang: http://docs.panchuang.net/PyTorch, официальная китайская учебная станция: http://pytorch.panchuang.net/OpenCV, официальный китайский документ: http://woshicver.com/