Artistic Portrait Drawing Generative Adversarial Network (APDrawingGAN)

cahyati sangaji (cahya)
6 min readJan 21, 2022

Cahyati Supriyati Sangaji (My Note)

Source : Ran Yi, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin. APDrawingGAN: Generating Artistic Portrait Drawings from Face Photos with Hierarchical GANs. Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 2019, pp. 10743–10752

Proses kerja dari APDrawingGAN dari gambar diatas dapat dijelaskan bahwa hirarki generator mengambil foto wajah sebagai inputan yang pada demo ini berasal dari data image lokal atau capture dari kamera. Data input ini didekomposisi menjadi Global Network (untuk struktur wajah global), enam Local Network (untuk empat bagian wajah lokal (mata kanan, mata kiri, hidung dan mulut), ramput dan bagian backgroud) dan Fusi Network. Output dari enam Local Network digabungkan ke dalam variable I local yang kemudian digabungkan dengan Global Network yang dideklarasikan menjadi variabel I global, jadi I local dan I global digabungkan yang kemudian menghasilkan output G atau output akhir. Loss fuction mencakup empat ketentuan, di mana DT Loss baru diperkenalkan untuk mempelajari gaya garis artistik yang lebih baik dan halus. Hirarki diskriminator membedakan apakah input adalah gambar artistic portrait real atau fake berdasarkan hasil klasifikasi dengan menggabungkan diskriminator global dan enam diskriminator lokal.

Proses Deep Learning ini merupakan salah satu dari varian teknologi untuk Generative Adversarial Network (GAN), yaitu mengubah gambar foto menjadi gambar potret. Gambaran ini seperti hasil karya dari seniman yang biasa menggambar sketsa kita dengan melihat langsung wajah atau posisi kita saat sedang di gambar, namun hasilnya menggunakan AI.

Demo ini dilakukan pada komputer leptop bukan dilakukan pada Jetson TX2, hal ini meyesuaikan dengan kondisi Work From Home. Hasilnya tetap cukup cepat untuk memproses variabel gambar dan hasil capture input dari kamera.

Demo ArtLine

Langkah awal mempersiapkan Library yang akan digunakan dengan library utama pada proses adalah fastai dan pytorch.

import fastai
from fastai.vision import *
from fastai.utils.mem import *
from fastai.vision import open_image, load_learner, image, torch
import numpy as np
import urllib.request
import PIL.Image
from io import BytesIO
import torchvision.transforms as T
from PIL import Image
import requests

Kemudian persiapkan function yang memproses gambar yang sebaiknya memiliki resolusi yang tinggi untuk menghasilkan sebuah gambar protret mirip seperti gambar lukisan tangan.

class FeatureLoss(nn.Module):
def __init__(self, m_feat, layer_ids, layer_wgts):
super().__init__()
self.m_feat = m_feat
self.loss_features = [self.m_feat[i] for i in layer_ids]
self.hooks = hook_outputs(self.loss_features, detach=False)
self.wgts = layer_wgts
self.metric_names = ['pixel',] + [f'feat_{i}' for i in range(len(layer_ids))
] + [f'gram_{i}' for i in range(len(layer_ids))]
def make_features(self, x, clone=False):
self.m_feat(x)
return [(o.clone() if clone else o) for o in self.hooks.stored]

def forward(self, input, target):
out_feat = self.make_features(target, clone=True)
in_feat = self.make_features(input)
self.feat_losses = [base_loss(input,target)]
self.feat_losses += [base_loss(f_in, f_out)*w
for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
self.feat_losses += [base_loss(gram_matrix(f_in), gram_matrix(f_out))*w**2 * 5e3
for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
self.metrics = dict(zip(self.metric_names, self.feat_losses))
return sum(self.feat_losses)

def __del__(self): self.hooks.remove()
def add_margin(pil_img, top, right, bottom, left, color):
width, height = pil_img.size
new_width = width + right + left
new_height = height + top + bottom
result = Image.new(pil_img.mode, (new_width, new_height), color)
result.paste(pil_img, (left, top))
return result

Setelah fuction sudah disiapkan, deklarasikan model yang akan digunakan dalam memproses gambar, pada demo ini menggunakan satu model.

learn=load_learner('C:/Users/LENOVO/Downloads/ArtLine/ArtLine-main', 'ArtLine_920.pkl')

Sebelum proses mengubah gambar foto menjadi gambar potret, disiapkan gamar foto yang akan diproses.

img = "C:/Users/LENOVO/Downloads/ArtLine/Image/2212111952.png"
open_image(img)
Source : https://assets.pikiran-rakyat.com/crop/3x282:688x907/x/photo/2020/10/10/2212111952.png

Selenjutnya melakukan proses mengubah gambar foto menjadi gambar potret dengan memanggil function yang sebelumnya sudah disiapkan, serta input variabel gambar foto yang sebelumnya kita deklarasikan.

p,img_hr,b = learn.predict(open_image(img))
show_image(img_hr, figsize=(9,9), interpolation='nearest');

Berikut hasil gambar protret yang dihasilkan dari proses Deep Learning.

Proses lain pada demo ini adalah mengubah gambar potret sebelumnya menjadi gambar seperti kartun yaitu dengan adanya proses pemberian warna pada gambar sketsa yang sebelumnya dibuat. Dengan ini gambar kartun menjadi seakan persis dengan karakter asli manusia di dunia nyata yang berawal dari gambar foto. Jika memang hasil dari pemprosesan gambar-gambar tersebut, sebenarnya ini akan membantu mempercepat pekerjaan para seniman sketsa atau animasi dengan tanpa menggambar mulai dari goresan awal.

import fastai
from fastai.vision import *
from fastai.utils.mem import *
from fastai.vision import open_image, load_learner, image, torch
import numpy as np
import urllib.request
import PIL.Image
from io import BytesIO
import torchvision.transforms as T
from PIL import Image
import requests
class FeatureLoss(nn.Module):
def __init__(self, m_feat, layer_ids, layer_wgts):
super().__init__()
self.m_feat = m_feat
self.loss_features = [self.m_feat[i] for i in layer_ids]
self.hooks = hook_outputs(self.loss_features, detach=False)
self.wgts = layer_wgts
self.metric_names = ['pixel',] + [f'feat_{i}' for i in range(len(layer_ids))
] + [f'gram_{i}' for i in range(len(layer_ids))]

def make_features(self, x, clone=False):
self.m_feat(x)
return [(o.clone() if clone else o) for o in self.hooks.stored]

def forward(self, input, target):
out_feat = self.make_features(target, clone=True)
in_feat = self.make_features(input)
self.feat_losses = [base_loss(input,target)]
self.feat_losses += [base_loss(f_in, f_out)*w
for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
self.feat_losses += [base_loss(gram_matrix(f_in), gram_matrix(f_out))*w**2 * 5e3
for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
self.metrics = dict(zip(self.metric_names, self.feat_losses))
return sum(self.feat_losses)

def __del__(self): self.hooks.remove()

def add_margin(pil_img, top, right, bottom, left, color):
width, height = pil_img.size
new_width = width + right + left
new_height = height + top + bottom
result = Image.new(pil_img.mode, (new_width, new_height), color)
result.paste(pil_img, (left, top))
return result

Seperti proses sebelumnya lakukan persiapan fuction untuk memproses gambar. Kemudian deklarasikan model yang akan digunakan, demo kali ini menggunakan dua model AI.

learn=load_learner('C:/Users/LENOVO/Downloads/ArtLine/ArtLine-main', 'ArtLine_920.pkl')
learn_c=load_learner('C:/Users/LENOVO/Downloads/ArtLine/ArtLine-main', 'Toon-Me_820.pkl')

Persiapan gambar foto yang akan diproses.

img = "C:/Users/LENOVO/Downloads/ArtLine/Image/Capture1.png"
open_image(img)

Lalu lakukan pemprosesan gambar dengan memanggil fuction yang telah disiapkan dengan input gambar potret yang telah disiapkan sebelumnya.

p,img_hr,b = learn_c.predict(open_image(img))
show_image(img_hr, figsize=(9,9), interpolation='nearest');

Berikut pengambaran hasil proses menjadi gambar kartun. Hasil pada demo kali ini memang tidak sempurna karena resolusi foto awal yang digunakan ternyata masih kurang bagus, namun hasilnya mewakili proses penggambaran kartun menggunakan library fastai.

Kemudian dilakukan percobaan untuk mendapatkan hasil dari input awal menggunakan capture dari kamera leptop. Dari demo ini karena bisa di katakan resolusi hasil capture masih kurang baik sehingga hasilnya juga masih harus disempurnakan, namun sudah mewakilkan bagaimana proses dan model berjalan.

import cv2
import time
cap = cv2.VideoCapture(0)

while True:
ret,frame=cap.read()
if ret == False:
break
cv2.imwrite('Frame0.jpg',frame)
frame = "C:/Users/LENOVO/Downloads/ArtLine/ArtLine-main/Frame0.jpg"
p,img_hr,b = learn.predict(open_image(frame))
show_image(img_hr, figsize=(9,9), interpolation='nearest');
cv2.destroyAllWindows()
time.sleep(1)
break

cap.release()
# Destroy all the windows

Berikut hasil dari capture kamera menjadi gambar sketsa.

Selanjutnya proses dari capture kamera menjadi gambar kartun. Hasil ini kurang maksimal karena capture dari image sketsa juga memberikan hasil yang kurang tepat, yang berpengaruh dari resolusi gambar yang dihasilkan.

p,img_hr,b = learn_c.predict(open_image(img))
show_image(img_hr, figsize=(9,9), interpolation='nearest');

Terakhir video dari proses demo berjalan yang memberikan gamaran bagaimana proses berjalan dan proses berjalan menggunakan laptop masih bisa dilakukan dengan input image.

--

--