Виртуальная Примерочная В Opencv

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

Однако по статистике с каждым годом доля онлайн-заказов в интернет-магазинах одежды и обуви растёт, но и доля возвратов тоже растёт, она составляет 50–70% — это огромные логистические затраты, которые можно существенно сократить, если воспользовавшись онлайн-примерочной.

Представьте, что вы загружаете свою фотографию, выбираете наряд, и он переносится на ваше изображение.

Виртуальные примерочные уже есть, они работают достаточно успешно.

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

Мы решили это исправить и поддержать одну из сетей в библиотеке OpenCV. Что из этого получилось, вы можете увидеть в virtual_try_on.py образец.



Виртуальная примерочная в OpenCV

Результат не идеален, но в этой области считается неплохим.

Если вы хотите узнать, как работает виртуальная примерочная и с какими трудностями мы столкнулись при интеграции модели в OpenCV — добро пожаловать под кат! Мы выбрали нейросеть 2019 года КП-ВТОН с довольно хорошим визуальным результатом.

По сравнению со своими аналогами CP-VTON интересен тем, что может достаточно точно передавать форму одежды в формируемом изображении, при этом особенности одежды (рисунок, логотип и фактура) не теряются при передаче.

Некоторые подобные сети используют 3D-модели человека, для получения которых требуется 3D-сканер.

Этот факт существенно сужает диапазон применимости модели.

Также большим плюсом является наличие кода на github. А вот авторы КП-ВТОН репозитории Они предоставляют только скрипты для обучения и тестирования, демо-версии, чтобы опробовать сеть на своих фотографиях, нет. Мы сами обучили сеть и сделали ее общедоступной.



Принцип действия

Модель КП-ВТОН состоит из двух субмодулей: ГММ (Geometric Matching Module) — модуль деформации одежды в соответствии с позой человека и ТОМ (Try-On Module) — модуль переноса деформированной одежды на изображение человека.

Обучение GMM требует тройного

Виртуальная примерочная в OpenCV

, а для ТОМ -

Виртуальная примерочная в OpenCV

,

Виртуальная примерочная в OpenCV

- образ человека,

Виртуальная примерочная в OpenCV

- изображение одежды,

Виртуальная примерочная в OpenCV

- выход ГММ,

Виртуальная примерочная в OpenCV

- основная истина (человек в одежде

Виртуальная примерочная в OpenCV

),

Виртуальная примерочная в OpenCV

- основная истина (деформированная одежда, полученная путем наложения маски одежды на

Виртуальная примерочная в OpenCV

).

Но такие тройки собрать достаточно сложно; обычно есть только

Виртуальная примерочная в OpenCV

И

Виртуальная примерочная в OpenCV

.

Решение этой проблемы было предложено в одной из предыдущих работ. ВИТОН , авторы статьи вместо этого

Виртуальная примерочная в OpenCV

на вход сети был подан тензор с описанием человека

Виртуальная примерочная в OpenCV

.

При создании

Виртуальная примерочная в OpenCV

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

Такой подход позволяет избежать показа в сети эталонного изображения человека в желаемой одежде.

Таким образом, GMM принимает в качестве входных данных

Виртуальная примерочная в OpenCV

и генерирует деформированную одежду

Виртуальная примерочная в OpenCV

, который во время обучения сравнивается с

Виртуальная примерочная в OpenCV

.

ТОМ принимает ввод

Виртуальная примерочная в OpenCV

, и сетевой выход

Виртуальная примерочная в OpenCV

по сравнению с

Виртуальная примерочная в OpenCV

.

Рассмотрим подробнее формирование тензора

Виртуальная примерочная в OpenCV

.

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

Сначала фотография ищется по ключевым точкам с помощью сети.

Открытая поза .

Для получения бинарной маски тела человека используется семантическая сегментация одежды и частей тела.

Эта задача решается с помощью модели LIP_JPPNet .

В процессе поддержки в OpenCV был добавлен (независимый) образец.

human_parsing.py .

Для маски тела берутся все ненулевые пиксели, для маски головы берутся пиксели, соответствующие классам: лицо, солнцезащитные очки, головной убор и волосы.

Затем маска тела размывается, а маска головы накладывается на входное изображение.



Виртуальная примерочная в OpenCV

Давайте посмотрим на работу модулей.

ГММ используется для изменения формы желаемой одежды в зависимости от позы человека.

В процессе работы сеть самостоятельно извлекает ключевые признаки из изображения одежды и тензора, описывающего человека, нормализует признаки с помощью

Виртуальная примерочная в OpenCV

.

Рассчитывается корреляция признаков и прогнозируется вектор параметров пространственного преобразования.

В результате постобработки из него генерируется деформационная сетка исходного изображения одежды.

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

Сравнить полученную деформацию одежды

Виртуальная примерочная в OpenCV

С

Виртуальная примерочная в OpenCV

использовал

Виртуальная примерочная в OpenCV

.



Виртуальная примерочная в OpenCV

Модуль ТОМ переносит деформированную одежду в изображение человека.

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

Unet избавляется от этого, делая переходы более плавными.

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

Сеть представляет собой последовательность сверток и объединений, которые уменьшают пространственное разрешение изображения.

А затем разрешение увеличивается с помощью последовательности Upsample и свертки.

Кодировщиком в сети является предварительно обученный ВГГ-19. Чтобы выходное изображение не было слишком размытым, используется следующий подход. Унет предсказывает образ человека

Виртуальная примерочная в OpenCV

и составная маска

Виртуальная примерочная в OpenCV

.

Маска затем сочетается с деформированной одеждой.



Виртуальная примерочная в OpenCV

и накладывается на

Виртуальная примерочная в OpenCV

, в сочетании с обратной маской

Виртуальная примерочная в OpenCV

и полученное изображение

Виртуальная примерочная в OpenCV

.



Виртуальная примерочная в OpenCV



Виртуальная примерочная в OpenCV

— признак поэлементного умножения матрицы.



Виртуальная примерочная в OpenCV

При обучении сети основная цель модуля Try-On — минимизировать несоответствие.



Виртуальная примерочная в OpenCV

С

Виртуальная примерочная в OpenCV

.

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

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

Чтобы избежать этих недостатков, используйте комбинацию

Виртуальная примерочная в OpenCV

С потеря восприятия .

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

VGG также чувствителен к резким изменениям яркости пикселей — это позволяет устранить размытость изображения за счет увеличения значения функции потерь в таких картинках.



Реализация в OpenCV

Для работы сети помимо изображения человека и одежды также требуется изображение со смысловой сегментацией частей человеческого тела и одежды на нем и файл с ключевыми точками человеческого тела.

Авторы статьи использовали json-файлы с сохраненными точками человеческого тела, полученные с помощью сети OpenPose от Caffe, и изображения с сегментацией из разметки набора данных LIP. Чтобы демо было удобно использовать, мы делаем поиск по ключевым точкам и сегментацию на лету, поэтому пользователю для входа достаточно только фото человека и изображения новой одежды.

  
  
  
   

python3 virtual_try_on.py -i person_img.jpg -c cloth.jpg

При портировании сети на OpenCV пришлось убрать всю предобработку через PIL. Вот тут-то и произошли чудеса с сегментацией.

Набор данных LIP представляет изображения в оттенках серого, где интенсивность пикселей соответствует классу объекта.

А при загрузке датасета для CP-VTON те же изображения уже в цвете.

Считывается трехканальное изображение, но затем производится работа с одноканальными изображениями:

shape = (segm > 0).

astype(np.float32) head = (segm == 1).

astype(np.float32) + \ (segm == 2).

astype(np.float32) + \ (segm == 4).

astype(np.float32) + \ (segm == 13).

astype(np.float32) cloth = (segm == 5).

astype(np.float32) + \ (segm == 6).

astype(np.float32) + \ (segm == 7).

astype(np.float32)

Оказывается, PIL может хранить цветное изображение и кодировку, с помощью которой оно было получено.

Перевод надписей в цвета находился в human_colormap.mat. Как их оттуда прочитать? Я не хотел устанавливать Matlab. К счастью, в scipy есть загрузчик для таких файлов.

Потратив немного (много) времени на эти махинации, мы смогли извлечь из сегментации маску тела и головы.

Более того.

Чтобы размыть маску, ее сначала уменьшают в 16 раз, затем возвращают к исходным размерам.



mask = mask.resize((width // 16, height // 16), Image.BILINEAR) mask = mask.resize((width, height), Image.BILINEAR)

Получаем маску в оттенках серого.

Для этого используется билинейная интерполяция.

Кажется, при портировании на OpenCV будет проще.

Мы заменили PIL resize на cv.resize и получили совершенно другой результат.

Виртуальная примерочная в OpenCV



Виртуальная примерочная в OpenCV

Слева — маска, полученная посредством изменения размера PIL, справа — cv.resize. Маски оказались совершенно разные, а как насчет результата сети? В общем, смотрите сами.



Виртуальная примерочная в OpenCV



Виртуальная примерочная в OpenCV

Слева — результат, полученный при использовании маски с PIL resize, справа — cv.resize. Выглядит немного грустно, не хотелось бы так уродовать людям руки.

Что это за билинейная интерполяция? После долгих поисков я ничего не смог найти.

Оставался последний, но верный способ — посмотреть исходники Си.

Там мы смогли увидеть, что билинейное изменение размера выглядит вовсе не как билинейное, а как площадное.

Размер ядра зависит от масштабного коэффициента, в нашем случае ядро имело размер 33 = 16 * 2 + 1, а в OpenCV ядро фиксированного размера — 3. При этом мы заметили, что пиксель значения различаются только при уменьшении размеров, а при после восстановления результаты достаточно близки.

Но смена типа интерполяции все равно не помогла добиться желаемого результата.

Давайте посмотрим дальше.

Коэффициенты интерполяции рассчитываются очень странным образом; они не симметричны.

Нам никогда не удавалось смоделировать это.

Поэтому мне пришлось написать небольшой класс с таким типом интерполяции: Реализация билинейной интерполяции из PIL

class BilinearFilter(object): """ PIL bilinear resize implementation image = image.resize((image_width // 16, image_height // 16), Image.BILINEAR) """ def _precompute_coeffs(self, inSize, outSize): filterscale = max(1.0, inSize / outSize) ksize = int(np.ceil(filterscale)) * 2 + 1 kk = np.zeros(shape=(outSize * ksize, ), dtype=np.float32) bounds = np.empty(shape=(outSize * 2, ), dtype=np.int32) centers = (np.arange(outSize) + 0.5) * filterscale + 0.5 bounds[::2] = np.where(centers - filterscale < 0, 0, centers - filterscale) bounds[1::2] = np.where(centers + filterscale > inSize, inSize, centers + filterscale) - bounds[::2] xmins = bounds[::2] - centers + 1 points = np.array([np.arange(row) + xmins[i] for i, row in enumerate(bounds[1::2])]) / filterscale for xx in range(0, outSize): point = points[xx] bilinear = np.where(point < 1.0, 1.0 - abs(point), 0.0) ww = np.sum(bilinear) kk[xx * ksize : xx * ksize + bilinear.size] = np.where(ww == 0.0, bilinear, bilinear / ww) return bounds, kk, ksize def _resample_horizontal(self, out, img, ksize, bounds, kk): for yy in range(0, out.shape[0]): for xx in range(0, out.shape[1]): xmin = bounds[xx * 2 + 0] xmax = bounds[xx * 2 + 1] k = kk[xx * ksize : xx * ksize + xmax] out[yy, xx] = np.round(np.sum(img[yy, xmin : xmin + xmax] * k)) def _resample_vertical(self, out, img, ksize, bounds, kk): for yy in range(0, out.shape[0]): ymin = bounds[yy * 2 + 0] ymax = bounds[yy * 2 + 1] k = kk[yy * ksize: yy * ksize + ymax] out[yy] = np.round(np.sum(img[ymin : ymin + ymax, 0:out.shape[1]] * k[:, np.newaxis], axis=0)) def imaging_resample(self, img, xsize, ysize): height, width, *args = img.shape bounds_horiz, kk_horiz, ksize_horiz = self._precompute_coeffs(width, xsize) bounds_vert, kk_vert, ksize_vert = self._precompute_coeffs(height, ysize) out_hor = np.empty((img.shape[0], xsize), dtype=np.uint8) self._resample_horizontal(out_hor, img, ksize_horiz, bounds_horiz, kk_horiz) out = np.empty((ysize, xsize), dtype=np.uint8) self._resample_vertical(out, out_hor, ksize_vert, bounds_vert, kk_vert) return out



Результаты

В целом получился довольно интересный конвейер из 4-х сетей, полученных от разных фреймворков, но работающих вместе в OpenCV. При тестировании сети на реальных фотографиях мы заметили несколько особенностей сети.

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

Их руки становятся более женственными, а переход от головы к телу имеет очень яркую границу.

Также для получения качественного результата необходимо загрузить фото с пропорциональным соотношением сторон 256 на 192, иначе сеть прибавит пару килограммов.

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

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

P.S. В мае 2020 года OpenCV отмечает свое 20-летие.

В этом году мы планируем написать больше статей и придумать другие мероприятия.

Следите за новостями! Теги: #Машинное обучение #Интернет вещей #открытый исходный код #искусственный интеллект #глубокое обучение #OpenCV #индустрия моды

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.