简介
和CelebA类似,使用ACGAN生成二次元头像,并且用多个条件进行控制
数据
图片爬取自http://getchu.com/,是一个日本二次元游戏网站,包含大量游戏人物立绘,共爬取31,970张
头像截取
之前介绍的dlib可用于提取人脸,但不适用于二次元头像
使用OpenCV从每张图片中截取头像部分,用到以下项目,https://github.com/nagadomi/lbpcascade_animeface
对于检测结果适当放大范围,以包含更多人物细节
# -*- coding: utf-8 -*-
import cv2
cascade = cv2.CascadeClassifier('lbpcascade_animeface.xml')
image = cv2.imread('imgs/二次元头像示例.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
faces = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(64, 64))
for i, (x, y, w, h) in enumerate(faces):
cx = x + w // 2
cy = y + h // 2
x0 = cx - int(0.75 * w)
x1 = cx + int(0.75 * w)
y0 = cy - int(0.75 * h)
y1 = cy + int(0.75 * h)
if x0 < 0:
x0 = 0
if y0 < 0:
y0 = 0
if x1 >= image.shape[1]:
x1 = image.shape[1] - 1
if y1 >= image.shape[0]:
y1 = image.shape[0] - 1
w = x1 - x0
h = y1 - y0
if w > h:
x0 = x0 + w // 2 - h // 2
x1 = x1 - w // 2 + h // 2
w = h
else:
y0 = y0 + h // 2 - w // 2
y1 = y1 - h // 2 + w // 2
h = w
face = image[y0: y0 + h, x0: x0 + w, :]
face = cv2.resize(face, (128, 128))
cv2.imwrite('face_%d.jpg' % i, face)
标签提取
使用Illustration2Vec
从二次元图片中抽取丰富的标签,https://github.com/rezoo/illustration2vec
Illustration2Vec用到chainer
这个深度学习框架,以及一些其他库,如果没有则安装
pip install chainer Pillow scikit-image
Illustration2Vec可以完成以下三项功能:
- 将每张图片表示为一个4096维的向量
- 指定阈值,并提取概率高于阈值的标签
- 指定一些标签,并返回对应的概率
举个例子,提取全部可能的标签,以0.5为阈值
# -*- coding: utf-8 -*-
import i2v
from imageio import imread
illust2vec = i2v.make_i2v_with_chainer('illust2vec_tag_ver200.caffemodel', 'tag_list.json')
img = imread('imgs/二次元头像示例.jpg')
tags = illust2vec.estimate_plausible_tags([img], threshold=0.5)
print(tags)
tags = illust2vec.estimate_specific_tags([img], ['blue eyes', 'red hair'])
print(tags)
也可以指定标签并获取对应的概率
[{'blue eyes': 0.9488178491592407, 'red hair': 0.0025324225425720215}]
预处理
在服务器上处理全部图片,即截取头像、提取标签
加载库
# -*- coding: utf-8 -*-
import i2v
import cv2
import glob
import os
from imageio import imread
from tqdm import tqdm
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pickle
读取图片路径
images = glob.glob('characters/*.jpg')
print(len(images))
加载两个模型
illust2vec = i2v.make_i2v_with_chainer('illust2vec_tag_ver200.caffemodel', 'tag_list.json')
cascade = cv2.CascadeClassifier('lbpcascade_animeface.xml')
OUTPUT_DIR = 'faces/'
if not os.path.exists(OUTPUT_DIR):
os.mkdir(OUTPUT_DIR)
提取全部头像,共检测到27772张
num = 0
for x in tqdm(range(len(images))):
img_path = images[x]
image = cv2.imread(img_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
faces = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(64, 64))
for (x, y, w, h) in faces:
cx = x + w // 2
cy = y + h // 2
x0 = cx - int(0.75 * w)
x1 = cx + int(0.75 * w)
y0 = cy - int(0.75 * h)
y1 = cy + int(0.75 * h)
if x0 < 0:
x0 = 0
if y0 < 0:
y0 = 0
if x1 >= image.shape[1]:
x1 = image.shape[1] - 1
if y1 >= image.shape[0]:
y1 = image.shape[0] - 1
w = x1 - x0
h = y1 - y0
if w > h:
x0 = x0 + w // 2 - h // 2
x1 = x1 - w // 2 + h // 2
w = h
else:
y0 = y0 + h // 2 - w // 2
y1 = y1 - h // 2 + w // 2
h = w
face = image[y0: y0 + h, x0: x0 + w, :]
face = cv2.resize(face, (128, 128))
cv2.imwrite(os.path.join(OUTPUT_DIR, '%d.jpg' % num), face)
num += 1
print(num)
感兴趣的标签包括以下34个:
- 13种头发颜色:blonde hair, brown hair, black hair, blue hair, pink hair, purple hair, green hair, red hair, silver hair, white hair, orange hair, aqua hair, grey hair
- 5种发型:long hair, short hair, twintails, drill hair, ponytail
- 10种眼睛颜色:blue eyes, red eyes, brown eyes, green eyes, purple eyes, yellow eyes, pink eyes, aqua eyes, black eyes, orange eyes
- 6种其他属性:blush, smile, open mouth, hat, ribbon, glasses
头发颜色、发型和眼睛颜色取概率最高的一种,其他属性概率高于0.25则以存在处理
fw = open('face_tags.txt', 'w')
tags = ['blonde hair', 'brown hair', 'black hair',