Apakah Anda memiliki barang yang Anda sukai di toko online, tetapi tidak ingin membelinya tanpa mencobanya? Tentu saja, di beberapa toko ada peluang untuk mencoba pakaian setelah memesan sebelum pembayaran. Namun, menurut statistik, pangsa pesanan online di toko pakaian dan sepatu online meningkat setiap tahun, tetapi bagian pengembalian juga meningkat, jumlahnya mencapai 50-70% - ini adalah biaya logistik yang sangat besar yang dapat dikurangi secara signifikan menggunakan ruang pas online. Bayangkan Anda mengunggah foto Anda, memilih pakaian dan itu ditransfer ke gambar Anda. Kamar pas virtual untuk sepatu sudah ada, mereka bekerja dengan cukup sukses. Beberapa waktu lalu, kami tertarik dengan topik ini, bagaimana dengan pakaian? Karya-karya semacam itu juga ada, tetapi yang kurang berhasil, di banyak di antaranya, selain artikel, tidak ada yang dapat ditemukan,Orang hanya bisa memimpikan contoh yang berhasil. Kami memutuskan untuk memperbaikinya dan mendukung salah satu jaringan di pustaka OpenCV. Apa yang datang dari ini dapat dilihat disampel virtual_try_on.py .

Hasilnya tidak sempurna, tetapi di daerah ini dianggap cukup baik.
Jika Anda ingin tahu bagaimana ruang pas virtual bekerja dan kesulitan apa yang kami temui ketika mengintegrasikan model ke OpenCV - selamat datang di kucing!
2019 CP-VTON . CP-VTON , , (, ). 3D , 3D-. . github. CP-VTON , , .
.
CP-VTON : GMM (Geometric Matching Module) β TOM (Try-On Module) β .
GMM , TOM β , β , β , β GMM, β ground truth ( ), β ground truth ( , ). , . VITON, . , , , , (, , ). . , GMM , . TOM , .
. , . OpenPose. . LIP_JPPNet. OpenCV () sample human_parsing.py.
, β , : , , . , .

.
GMM . , , . . . , . .

TOM . Unet. , . Unet , . , Unet . , . Upsample . (encoder) VGG-19. . Unet . , .
β .

Try-On β . . , , . perceptual loss. 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 .

, PIL resize, β cv.resize.
, ? .

, PIL resize, β cv.resize.
, . ? , . , β . , bilinear resize bilinear, area. scale factor, 33 = 16 * 2 + 1, OpenCV β 3. , , . . . , . . :
PILclass 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, . sample . , - , .
P.S. 2020 OpenCV 20-. . !