Введение
Представьте модели CycleGAN, которые можно использовать для реализации различных задач перевода непарных изображений и выполнения задач преобразования пола.
принцип
В отличие от pix2pix, CycleGAN не требует строго парных изображений, а нуждается только в двух категориях (доменах), например, одна папка заполнена картинками яблок, а другая - оранжевыми картинками.
Используя два типа изображений, A и B, вы можете реализовать перевод A в B и перевод B в A.
Подробные примеры и введения представлены на официальном сайте газеты,junyanz.github.io/CycleGAN/, такие как яблоки и апельсины, лошади и зебры, лето и зима, фотографии и произведения искусства и т. д.
и официальный проект Github для статьи,GitHub.com/military training/C-сторона…, реализованный с помощью PyTorch
CycleGAN состоит из двух генераторов G и F и двух дискриминаторов Dx и Dy.
G принимает истинное X и выдает ложное Y, то есть завершает преобразование из X в Y; F принимает истинное Y и выводит ложное X, то есть завершает преобразование из Y в X; Dx принимает истинное и ложное X и различает, и Dy принимает true False Y и различает
Функция потерь CycleGAN аналогична стандартной GAN, но записываются только два набора.
Кроме того, чтобы избежать проблемы коллапса режима, CycleGAN также учитывает потерю согласованности цикла (потеря согласованности цикла).
Таким образом, общая потеря CycleGAN выглядит следующим образом: G, F, Dx, Dy нуждаются в некоторых элементах потерь min и max соответственно.
выполнить
В конкретной реализации статьи используются два приема
- Используйте метод наименьших квадратов потерь, т. е. метод наименьших квадратов вместо стандартных потерь GAN.
- Взяв в качестве примера G, создайте коллекцию исторических поддельных изображений Y, например, 50 изображений. Каждый раз, когда G генерирует фальшивый Y, он добавляется к набору, а затем фальшивый Y случайным образом берется из набора и вводится в дискриминатор вместе с реальным Y. Таким образом, ложный набор Y представляет собой среднюю способность G генерировать Y из X, что делает обучение более стабильным.
Обучите модель CycleGAN, используя следующий проект:GitHub.com/van Huyanzhuo/C сторона…, в основном включающий несколько кодов:
-
build_data.py
: Организация данных изображений в файлы tfrecords. -
ops.py
: определяет несколько небольших сетевых модулей -
generator.py
: Определение генератора -
discriminator.py
: Определение дискриминатора -
model.py
: Определите CycleGAN с генератором и дискриминатором -
train.py
: код для обучения модели -
export_graph.py
: Упакуйте обученную модель в.pd
документ -
inference.py
: используйте упакованный.pb
Изображение перевода файла, т.е. использовать модель для вывода
Структура генератора и дискриминатора следующая, если вам интересно, вы можете прочитать исходный код проекта далее
гендерный переход
Тренируйте Cocalgan, который реализует гендерное преобразование, используя мужские картинки и женские фотографии в Celeba
Процесс изображения в наборе Celeba в DataSet256*256
размера и сохранены в мужских и женских папках в зависимости от пола, содержащих 84434 мужских изображения и 118165 женских изображений соответственно.
# -*- coding: utf-8 -*-
from imageio import imread, imsave
import cv2
import glob, os
from tqdm import tqdm
data_dir = 'data'
male_dir = 'data/male'
female_dir = 'data/female'
if not os.path.exists(data_dir):
os.mkdir(data_dir)
if not os.path.exists(male_dir):
os.mkdir(male_dir)
if not os.path.exists(female_dir):
os.mkdir(female_dir)
WIDTH = 256
HEIGHT = 256
def read_process_save(read_path, save_path):
image = imread(read_path)
h = image.shape[0]
w = image.shape[1]
if h > w:
image = image[h // 2 - w // 2: h // 2 + w // 2, :, :]
else:
image = image[:, w // 2 - h // 2: w // 2 + h // 2, :]
image = cv2.resize(image, (WIDTH, HEIGHT))
imsave(save_path, image)
target = 'Male'
with open('list_attr_celeba.txt', 'r') as fr:
lines = fr.readlines()
all_tags = lines[0].strip('\n').split()
for i in tqdm(range(1, len(lines))):
line = lines[i].strip('\n').split()
if int(line[all_tags.index(target) + 1]) == 1:
read_process_save(os.path.join('celeba', line[0]), os.path.join(male_dir, line[0])) # 男
else:
read_process_save(os.path.join('celeba', line[0]), os.path.join(female_dir, line[0])) # 女
использоватьbuild_data.py
Преобразование изображения в формат tfrecords
python CycleGAN-TensorFlow/build_data.py --X_input_dir data/male/ --Y_input_dir data/female/ --X_output_file data/male.tfrecords --Y_output_file data/female.tfrecords
использоватьtrain.py
Обучите модель CycleGAN
python CycleGAN-TensorFlow/train.py --X data/male.tfrecords --Y data/female.tfrecords --image_size 256
После начала обучения создается папка контрольных точек и подпапка на основе текущей даты и времени, например.20180507-0231
, включая те, которые используются для отображения тензорной доскиevents.out.tfevents
файл и некоторые файлы, связанные с моделью
Используйте tensorboard для просмотра сведений об обучении модели, выполните следующую команду для доступа к порту 6006.
tensorboard --logdir=checkpoints/20180507-0231
Ниже приведена страница IMAGES tensorboard после 185870 итераций.
Ограничения на количество итераций для обучения модели нет, поэтому, если вы чувствуете, что эффект хороший или количество итераций почти одинаково, вы можете прекратить обучение
использоватьexport_graph.py
упаковать модель в.pb
файлы, сгенерированные файлы находятся в предварительно подготовленной папке
python CycleGAN-TensorFlow/export_graph.py --checkpoint_dir checkpoints/20180507-0231/ --XtoY_model male2female.pb --YtoX_model female2male.pb --image_size 256
пройти черезinference.py
Используйте модели для обработки изображений
python CycleGAN-TensorFlow/inference.py --model pretrained/male2female.pb --input Trump.jpg --output Trump_female.jpg --image_size 256
python CycleGAN-TensorFlow/inference.py --model pretrained/female2male.pb --input Hillary.jpg --output Hillary_male.jpg --image_size 256
Используйте модель в коде для обработки нескольких изображений
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
from model import CycleGAN
from imageio import imread, imsave
import glob
import os
image_file = 'face.jpg'
W = 256
result = np.zeros((4 * W, 5 * W, 3))
for gender in ['male', 'female']:
if gender == 'male':
images = glob.glob('../faces/male/*.jpg')
model = '../pretrained/male2female.pb'
r = 0
else:
images = glob.glob('../faces/female/*.jpg')
model = '../pretrained/female2male.pb'
r = 2
graph = tf.Graph()
with graph.as_default():
graph_def = tf.GraphDef()
with tf.gfile.FastGFile(model, 'rb') as model_file:
graph_def.ParseFromString(model_file.read())
tf.import_graph_def(graph_def, name='')
with tf.Session(graph=graph) as sess:
input_tensor = graph.get_tensor_by_name('input_image:0')
output_tensor = graph.get_tensor_by_name('output_image:0')
for i, image in enumerate(images):
image = imread(image)
output = sess.run(output_tensor, feed_dict={input_tensor: image})
with open(image_file, 'wb') as f:
f.write(output)
output = imread(image_file)
maxv = np.max(output)
minv = np.min(output)
output = ((output - minv) / (maxv - minv) * 255).astype(np.uint8)
result[r * W: (r + 1) * W, i * W: (i + 1) * W, :] = image
result[(r + 1) * W: (r + 2) * W, i * W: (i + 1) * W, :] = output
os.remove(image_file)
imsave('CycleGAN性别转换结果.jpg', result)
преобразование пола видео
Для видео определите лица, которые могут содержаться в каждом кадре, определите пол, соответствующий лицу, и используйте CycleGAN для завершения двустороннего преобразования пола.
Используйте следующие элементы для определения пола,GitHub.com/with4U/Возраст-а…, с помощью обучающей модели Keras можно определить пол и возраст лица
Например, используйте OpenCV для получения изображений с камеры, обнаружения лиц через dlib и получения возраста и пола, соответствующих каждому результату обнаружения.
# -*- coding: utf-8 -*-
from wide_resnet import WideResNet
import numpy as np
import cv2
import dlib
depth = 16
width = 8
img_size = 64
model = WideResNet(img_size, depth=depth, k=width)()
model.load_weights('weights.hdf5')
def draw_label(image, point, label, font=cv2.FONT_HERSHEY_SIMPLEX, font_scale=1, thickness=2):
size = cv2.getTextSize(label, font, font_scale, thickness)[0]
x, y = point
cv2.rectangle(image, (x, y - size[1]), (x + size[0], y), (255, 0, 0), cv2.FILLED)
cv2.putText(image, label, point, font, font_scale, (255, 255, 255), thickness)
detector = dlib.get_frontal_face_detector()
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
while True:
ret, image_np = cap.read()
image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)
img_h = image_np.shape[0]
img_w = image_np.shape[1]
detected = detector(image_np, 1)
faces = []
if len(detected) > 0:
for i, d in enumerate(detected):
x0, y0, x1, y1, w, h = d.left(), d.top(), d.right(), d.bottom(), d.width(), d.height()
cv2.rectangle(image_np, (x0, y0), (x1, y1), (255, 0, 0), 2)
x0 = max(int(x0 - 0.25 * w), 0)
y0 = max(int(y0 - 0.45 * h), 0)
x1 = min(int(x1 + 0.25 * w), img_w - 1)
y1 = min(int(y1 + 0.05 * h), img_h - 1)
w = x1 - x0
h = y1 - y0
if w > h:
x0 = x0 + w // 2 - h // 2
w = h
x1 = x0 + w
else:
y0 = y0 + h // 2 - w // 2
h = w
y1 = y0 + h
faces.append(cv2.resize(image_np[y0: y1, x0: x1, :], (img_size, img_size)))
faces = np.array(faces)
results = model.predict(faces)
predicted_genders = results[0]
ages = np.arange(0, 101).reshape(101, 1)
predicted_ages = results[1].dot(ages).flatten()
for i, d in enumerate(detected):
label = '{}, {}'.format(int(predicted_ages[i]), 'F' if predicted_genders[i][0] > 0.5 else 'M')
draw_label(image_np, (d.left(), d.top()), label)
cv2.imshow('gender and age', cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR))
if cv2.waitKey(25) & 0xFF == ord('q'):
cap.release()
cv2.destroyAllWindows()
break
Вышеупомянутые элементы и CycleGAN применяются к двунаправленному преобразованию пола видео. Сначала извлекаются лица в видео, и записывается количество кадров, позиции и соответствующие полы лиц. В видео 830 кадров, и обнаружено 721 лицо.
# -*- coding: utf-8 -*-
from wide_resnet import WideResNet
import numpy as np
import cv2
import dlib
import pickle
depth = 16
width = 8
img_size = 64
model = WideResNet(img_size, depth=depth, k=width)()
model.load_weights('weights.hdf5')
detector = dlib.get_frontal_face_detector()
cap = cv2.VideoCapture('../friends.mp4')
pos = []
frame_id = -1
while cap.isOpened():
ret, image_np = cap.read()
frame_id += 1
if len((np.array(image_np)).shape) == 0:
break
image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)
img_h = image_np.shape[0]
img_w = image_np.shape[1]
detected = detector(image_np, 1)
if len(detected) > 0:
for d in detected:
x0, y0, x1, y1, w, h = d.left(), d.top(), d.right(), d.bottom(), d.width(), d.height()
x0 = max(int(x0 - 0.25 * w), 0)
y0 = max(int(y0 - 0.45 * h), 0)
x1 = min(int(x1 + 0.25 * w), img_w - 1)
y1 = min(int(y1 + 0.05 * h), img_h - 1)
w = x1 - x0
h = y1 - y0
if w > h:
x0 = x0 + w // 2 - h // 2
w = h
x1 = x0 + w
else:
y0 = y0 + h // 2 - w // 2
h = w
y1 = y0 + h
face = cv2.resize(image_np[y0: y1, x0: x1, :], (img_size, img_size))
result = model.predict(np.array([face]))
pred_gender = result[0][0][0]
if pred_gender > 0.5:
pos.append([frame_id, y0, y1, x0, x1, h, w, 'F'])
else:
pos.append([frame_id, y0, y1, x0, x1, h, w, 'M'])
print(frame_id + 1, len(pos))
with open('../pos.pkl', 'wb') as fw:
pickle.dump(pos, fw)
cap.release()
cv2.destroyAllWindows()
Затем используйте CycleGAN, чтобы преобразовать лицо в исходном видео в противоположный пол и записать его в новый видеофайл.
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
from model import CycleGAN
from imageio import imread
import os
import cv2
import pickle
from tqdm import tqdm
with open('../pos.pkl', 'rb') as fr:
pos = pickle.load(fr)
cap = cv2.VideoCapture('../friends.mp4')
ret, image_np = cap.read()
out = cv2.VideoWriter('../output.mp4', -1, cap.get(cv2.CAP_PROP_FPS), (image_np.shape[1], image_np.shape[0]))
frames = []
while cap.isOpened():
ret, image_np = cap.read()
if len((np.array(image_np)).shape) == 0:
break
frames.append(cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB))
image_size = 256
image_file = 'face.jpg'
for gender in ['M', 'F']:
if gender == 'M':
model = '../pretrained/male2female.pb'
else:
model = '../pretrained/female2male.pb'
graph = tf.Graph()
with graph.as_default():
graph_def = tf.GraphDef()
with tf.gfile.FastGFile(model, 'rb') as model_file:
graph_def.ParseFromString(model_file.read())
tf.import_graph_def(graph_def, name='')
with tf.Session(graph=graph) as sess:
input_tensor = graph.get_tensor_by_name('input_image:0')
output_tensor = graph.get_tensor_by_name('output_image:0')
for i in tqdm(range(len(pos))):
fid, y0, y1, x0, x1, h, w, g = pos[i]
if g == gender:
face = cv2.resize(frames[fid - 1][y0: y1, x0: x1, :], (image_size, image_size))
output_face = sess.run(output_tensor, feed_dict={input_tensor: face})
with open(image_file, 'wb') as f:
f.write(output_face)
output_face = imread(image_file)
maxv = np.max(output_face)
minv = np.min(output_face)
output_face = ((output_face - minv) / (maxv - minv) * 255).astype(np.uint8)
output_face = cv2.resize(output_face, (w, h))
frames[fid - 1][y0: y1, x0: x1, :] = output_face
for frame in frames:
out.write(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
os.remove(image_file)
cap.release()
out.release()
cv2.destroyAllWindows()
Сгенерированный видеофайл содержит только изображения и не содержит звука, и его можно использоватьffmpeg
дальнейшая обработка
если нетffmpeg
затем скачать и установить,woohoo.ffmpeg.org/download.Contract…
Перейдите в командную строку и извлеките звук из исходного видео.
ffmpeg -i friends.mp4 -f mp3 -vn sound.mp3
Синтезируйте извлеченный звук и результирующее видео вместе
ffmpeg -i output.mp4 -i sound.mp3 combine.mp4
разное
Проект также предоставляет четыре обученные модели,GitHub.com/van Huyanzhuo/C сторона…, в том числе яблоки к апельсинам, апельсины к яблокам, кони к зебрам, зебры к коням, если интересно, можно попробовать
Использование CycleGAN может не только завершить преобразование между двумя типами изображений, но также реализовать преобразование между двумя объектами, например, перевод одного человека в другого человека.
Вы можете рассмотреть возможность извлечения изображений, соответствующих двум персонажам из фильма.После обучения CycleGAN вы можете перевести одного человека в другого.
Есть и более смелые попытки,Улучшение навыков вождения: использование GAN для удаления мозаики и одежды из (любовных) боевиков
Ссылаться на
- ЦиклГАН:junyanz.github.io/CycleGAN/
- ЦиклGAN-TensorFlow:GitHub.com/van Huyanzhuo/C сторона…
- Реализация Keras сети CNN для оценки возраста и пола:GitHub.com/with4U/Возраст-а…