Abstract: This case can be based on a father and mother’s face photo, to generate a photo of the child, and can adjust the parameters to see the appearance of children of different genders and ages.

This article is from The huawei cloud community “BabyGAN: Generating a Child’s photo from a parent’s photo”, by the light of Shan Hai.

This case can be based on a father and mother’s face photo, generate a photo of the child, and can adjust the parameters to see the appearance of children of different genders and ages.

When uploading photos of parents, try to upload photos that show their facial features and have a light background to ensure the effect of the photos.

This case is only for learning and communication. Do not use it for other purposes.

In addition, due to the imperfect technology, the generated child photos may be distorted or distorted, you can replace different parents photos, regenerate the child photos, until the satisfactory generation effect is achieved.

Let’s start by running the example step by step.

1. Install required modules

This step takes about 4 minutes

! pip install imutils moviepy dlibCopy the code

2. Download the code and model files

import os
import moxing as mox

root_dir = '/home/ma-user/work/ma_share/'
code_dir = os.path.join(root_dir, 'BabyGAN')
if not os.path.exists(os.path.join(root_dir, 'BabyGAN.zip')):
    mox.file.copy('obs://arthur-1/BabyGAN/BabyGAN.zip', os.path.join(root_dir, 'BabyGAN.zip'))
    os.system('cd %s; unzip BabyGAN.zip' % root_dir)

os.chdir(code_dir)
Copy the code

3. Load relevant modules and models

import cv2 import math import pickle import imageio import warnings import PIL.Image import numpy as np from glob import  glob from PIL import Image import tensorflow as tf from random import randrange import moviepy.editor as mpy import matplotlib.pyplot as plt from IPython.display import clear_output from moviepy.video.io.ffmpeg_writer import FFMPEG_VideoWriter import config import dnnlib import dnnlib.tflib as tflib from encoder.generator_model import Generator %matplotlib inline warnings.filterwarnings("ignore")Copy the code

Load the model file. This code block can only be executed once. If an error occurs, restart the kernel and run all the code again

tflib.init_tf() URL_FFHQ = "./karras2019stylegan-ffhq-1024x1024.pkl" with dnnlib.util.open_url(URL_FFHQ, cache_dir=config.cache_dir) as f: generator_network, discriminator_network, Gs_network = pickle.load(f) generator = Generator(Gs_network, batch_size=1, randomize_noise=False) model_scale = int(2 * (math.log(1024, 2) - 1)) age_direction = np.load('./ffhq_dataset/latent_directions/age.npy') horizontal_direction = np.load('./ffhq_dataset/latent_directions/angle_horizontal.npy') vertical_direction = np.load('./ffhq_dataset/latent_directions/angle_vertical.npy') eyes_open_direction = np.load('./ffhq_dataset/latent_directions/eyes_open.npy') gender_direction = np.load('./ffhq_dataset/latent_directions/gender.npy') smile_direction = np.load('./ffhq_dataset/latent_directions/smile.npy') def get_watermarked(pil_image: Image) -> Image: try: image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) (h, w) = image.shape[:2] image = np.dstack([image, Np.ones ((h, w), dtype="uint8") * 255) cv2.IMREAD_UNCHANGED) (fwH, WH = int(PCT * h * 2) wW = int((wH * fwW)/fwH * 0.1) watermark = cv2.resize(full_watermark, (wH, wW), interpolation=cv2.INTER_AREA) overlay = np.zeros((h, w, 4), dtype="uint8") (wH, wW) = watermark.shape[:2] overlay[h - wH - 10: h - 10, 10: Overlay = image.copy(overlay, 0.5, output, 1.0, 0) output) rgb_image = cv2.cvtColor(output, cv2.COLOR_BGR2RGB) return Image.fromarray(rgb_image) except: return pil_image def generate_final_images(latent_vector, direction, coeffs, i): new_latent_vector = latent_vector.copy() new_latent_vector[:8] = (latent_vector + coeffs * direction)[:8] new_latent_vector = new_latent_vector.reshape((1, 18, 512)) generator.set_dlatents(new_latent_vector) img_array = generator.generate_images()[0] img = PIL.Image.fromarray(img_array, 'RGB') if size[0] >= 512: img = get_watermarked(img) img_path = "./for_animation/" + str(i) + ".png" img.thumbnail(animation_size, PIL.Image.ANTIALIAS) img.save(img_path) face_img.append(imageio.imread(img_path)) clear_output() return img def generate_final_image(latent_vector, direction, coeffs): new_latent_vector = latent_vector.copy() new_latent_vector[:8] = (latent_vector + coeffs * direction)[:8] new_latent_vector = new_latent_vector.reshape((1, 18, 512)) generator.set_dlatents(new_latent_vector) img_array = generator.generate_images()[0] img = PIL.Image.fromarray(img_array, 'RGB') if size[0] >= 512: img = get_watermarked(img) img.thumbnail(size, PIL.Image.ANTIALIAS) img.save("face.png") if download_image == True: files.download("face.png") return img def plot_three_images(imgB, fs=10): f, axarr = plt.subplots(1, 3, figsize=(fs, fs)) axarr[0].imshow(Image.open('./aligned_images/father_01.png')) axarr[0].title.set_text("Father's photo") axarr[1].imshow(imgB) axarr[1].title.set_text("Child's photo") axarr[2].imshow(Image.open('./aligned_images/mother_01.png')) axarr[2].title.set_text("Mother's photo") plt.setp(plt.gcf().get_axes(), xticks=[], yticks=[]) plt.show()Copy the code

4. Prepare pictures of mom and Dad

In this case, a default parent photo has been prepared. In the file Resource Management window in the left sidebar, go to the ma_share/BabyGAN directory and then go to the father_image or mother_image directory to see the provided parent photo, as shown below:

If you need to change photos of your parents, see section 11 of this article, “Changing Photos of Your parents.”

if len(glob(os.path.join('./father_image', '*.jpg'))) ! = 1 or (not os.path.exists('./father_image/father.jpg')): Raise Exception(' Please prepare a photo of your father under ma_share/BabyGAN/father_image, And named father. JPG ') if len (glob (OS) path) join ('/mother_image ', '*.jpg)))! = 1 or (not os.path.exists('./mother_image/mother.jpg')): Raise Exception(' Please prepare a photo of your mother in ma_share/BabyGAN/father_image and name it mother.jpg')Copy the code

5. Capture the father’s face area and align it

! python align_images.py ./father_image ./aligned_imagesCopy the code

Check the father’s face

if os.path.isfile('./aligned_images/father_01.png'):
    pil_father = Image.open('./aligned_images/father_01.png')
    (fat_width, fat_height) = pil_father.size
    resize_fat = max(fat_width, fat_height) / 256
    display(pil_father.resize((int(fat_width / resize_fat), int(fat_height / resize_fat))))
else:
    raise ValueError('No face was found or there is more than one in the photo.')
Copy the code

6. Capture the mother’s face area and align it

! python align_images.py ./mother_image ./aligned_imagesCopy the code

Look at the mother’s face

if os.path.isfile('./aligned_images/mother_01.png'):
    pil_mother = Image.open('./aligned_images/mother_01.png')
    (mot_width, mot_height) = pil_mother.size
    resize_mot = max(mot_width, mot_height) / 256
    display(pil_mother.resize((int(mot_width / resize_mot), int(mot_height / resize_mot))))
else:
    raise ValueError('No face was found or there is more than one in the photo.')
Copy the code

7. Extracting facial features

This step takes about 3 minutes

! Py \ --early_stopping False \ --lr=0.25 \ --batch_size=2 \ --iterations=100 \ --output_video=False \ ./aligned_images \ ./generated_images \ ./latent_representations if len(glob(os.path.join('./generated_images', '*.png'))) == 2: first_face = np.load('./latent_representations/father_01.npy') second_face = np.load('./latent_representations/mother_01.npy') print("Generation of latent representation is complete! Now comes the fun part.") else: raise ValueError('Something wrong. It may be impossible to read the face in the photos. Upload other photos and try again.')Copy the code

8. Generate a photo of a family of three

Modify the gender_influence and person_age parameters in the code below

Gender_influence: Gender influencing factor (range: 0.01, 0.99). The closer the value is to 0, the greater the influence of the father’s appearance and the greater the influence of the mother’s appearance.

Person_age: age influence factor, value range [10, 50], set this value, will generate the face of the corresponding age of the child.

Each time you change the value of this parameter, rerun the following code block to generate a new photo of your child

Genes_influence = 0.8 # gender influence factor, value range [0.01, 0.99], the closer the value is to 0, the greater the influence of the father's appearance, conversely, the greater the influence of the mother. Person_age = 10 # age influence factor, value range [10, 50], set this value, Style = "Default" if style == "Father's photo": lr = ((np.arange(1, model_scale + 1) / model_scale) ** genes_influence).reshape((model_scale, 1)) rl = 1 - lr hybrid_face = (lr * first_face) + (rl * second_face) elif style == "Mother's photo": lr = ((np.arange(1, model_scale + 1) / model_scale) ** (1 - genes_influence)).reshape((model_scale, 1)) rl = 1 - lr hybrid_face = (rl * first_face) + (lr * second_face) else: hybrid_face = ((1 - genes_influence) * first_face) + (genes_influence * second_face) intensity = -((person_age / 5) - 6)  resolution = "512" size = int(resolution), int(resolution) download_image = False face = generate_final_image(hybrid_face, age_direction, intensity) plot_three_images(face, fs=15)Copy the code

9. Check your child’s age range

Please modify the gender_influence parameter in the code below. The gender_influence parameter ranges from 0.01 to 0.99. The closer the value is to 0, the greater the influence of the father’s appearance is, while the influence of the mother is.

Each time you change the value of this parameter, rerun the following code block

Gender_influence = 0.8 # (range: 0.01, 0.99). The closer the value is to 0, the greater the influence of the father's appearance is, and the greater the influence of the mother's appearance is! rm -rf ./for_animation ! mkdir ./for_animation face_img = [] hybrid_face = ((1 - gender_influence) * first_face) + (gender_influence * second_face) animation_resolution = "512" animation_size = int(animation_resolution), int(animation_resolution) frames_number = 50 download_image = False for i in range(0, frames_number, 1): intensity = (8 * (i / (frames_number - 1))) - 4 generate_final_images(hybrid_face, age_direction, intensity, i) clear_output() print(str(i) + " of {} photo generated".format(str(frames_number))) for j in reversed(face_img): Face_img. appEnd (J) Automatic_download = False if gender_influence <= 0.3: Animation_name = "boy.mp4" Elif gender_influence >= 0.7: animation_name = "girl.mp4" else: animation_name = "boy.mp4" Elif gender_influence >= 0.7: animation_name = "girl.mp4" else: animation_name = "animation.mp4" imageio.mimsave('./for_animation/' + animation_name, face_img) clear_output() display(mpy.ipython_display('./for_animation/' + animation_name, height=400, autoplay=1, loop=1))Copy the code

10. Check your child’s gender

Modify the person_age parameter in the code below, which is an age-influencing factor in the range [10, 50], to generate the face of a child of that age.

Each time you change the value of this parameter, rerun the following code block

Person_age = 10 # The age of the child. The value ranges from 10 to 50. When set to this value, the face of the child will be generated. rm -rf ./for_animation ! mkdir ./for_animation face_img = [] intensity = -((person_age / 5) - 6) animation_resolution = "512" animation_size = Int (animation_resolution), int(animation_resolution) frames_number = 50 # Value range [10, 50] Download_image = False for I in range(1, frames_number): gender_influence = i / frames_number hybrid_face = ((1 - gender_influence) * first_face) + (gender_influence * second_face) face = generate_final_images(hybrid_face, age_direction, intensity, i) clear_output() print(str(i) + " of {} photo generated".format(str(frames_number))) for j in reversed(face_img): face_img.append(j) animation_name = str(person_age) + "_years.mp4" imageio.mimsave('./for_animation/' + animation_name, face_img) clear_output() display(mpy.ipython_display('./for_animation/' + animation_name, height=400, autoplay=1, loop=1))Copy the code

11. Change photos of mom and Dad

Next, you can upload the parent photos you’re interested in to the father_image and mother_image directories and run the code again to generate a new one.

You need to follow these rules and procedures:

1. Go to the ma_share/BabyGAN directory by referring to the following figure.

2. Upload a photo of your father to father_image as father.jpg. (If you do not know how to upload files to JupyterLab, please check this document)

3. Upload a photo of your mother to the mother_image directory and name it mother.jpg.

Father_image and mother_image directories both allow only one photo;

5. Re-run the code in Steps 4 to 10.

Click to follow, the first time to learn about Huawei cloud fresh technology ~