精华内容
下载资源
问答
  • 如何利用CycleGAN实现男女性别转换

    千次阅读 2019-11-26 22:17:29
    介绍 CycleGAN网络具有很强大的风格迁移功能。能够实现非常深层次的风格转换。比如男性图片女性化或者...可以直接运行,实现图片中头像识别和对应性别转换。可以体验一下生成对抗网络的趣味。 对网络感兴趣,以及想...

    介绍

    CycleGAN网络具有很强大的风格迁移功能。能够实现非常深层次的风格转换。比如男性图片女性化或者女性图片男性化。

    先上效果图:
    在这里插入图片描述
    下面简单谈一谈实现原理。

    网络结构

    在这里插入图片描述
    网络结构如图所示,通过两个循环使用的生成器来进行风格迁移。由此实现了非常神奇的效果。

    下面结合代码来详细解释一下网络结构。训练生成对抗网络的深度学习框架为Pytorch

    1. 残差模块定义

    class ResidualBlock(nn.Module):
        def __init__(self, in_features):
            super(ResidualBlock, self).__init__()
    
            # 残差模块不改变shape
            conv_block = [  nn.ReflectionPad2d(1),  # 构建残差模块的时候使用映射填充的形式
                            nn.Conv2d(in_features, in_features, 3),
                            nn.InstanceNorm2d(in_features),     # 不使用BatchNorm而是使用InstanceNorm
                            nn.ReLU(inplace=True),
                            nn.ReflectionPad2d(1),
                            nn.Conv2d(in_features, in_features, 3),
                            nn.InstanceNorm2d(in_features)  ]
    
            self.conv_block = nn.Sequential(*conv_block)
    
        def forward(self, x):
            return x + self.conv_block(x)
    

    残差模块的定义没有太多需要说明的地方,就是有一点需要注意的是。我们在风格迁移中,不再使用BatchNorm而是使用InstanceNorm。
    在这里插入图片描述
    BN是将每一个batch的每一个通道的每一组图片求mean和var, IN是将单独一个图片的一个通道的数据求mean和var。 区别就是一个是对batch求,一个是对一个图片求。风格迁移中,为了保证风格,通常都对每一个图片单独处理。 CycleGAN网络中,每一个batch只有一张 图片,所以使用InstanceNorm。

    2. 定义生成器

    class Generator(nn.Module):
        def __init__(self, input_nc, output_nc, n_residual_blocks=9):
            """
            定义生成网络
            参数:
                input_nc                    --输入通道数
                output_nc                   --输出通道数
                n_residual_blocks           --残差模块数量
            """
            super(Generator, self).__init__()
    
            # 初始化卷积模块
            # 因为使用ReflectionPad扩充
            # 所以输入是3*256*256
            # 输出是64*256*256
            model = [   nn.ReflectionPad2d(3),
                        nn.Conv2d(input_nc, 64, 7),
                        nn.InstanceNorm2d(64),
                        nn.ReLU(inplace=True) ]
    
            # 进行下采样
            # 第一个range:输入是64*256*256,输出是128*128*128
            # 第二个range:输入是128*128*128,输出是256*64*64
    
            in_features = 64
            out_features = in_features*2
            for _ in range(2):
                model += [  nn.Conv2d(in_features, out_features, 3, stride=2, padding=1),
                            nn.InstanceNorm2d(out_features),
                            nn.ReLU(inplace=True) ]
                in_features = out_features
                out_features = in_features*2
    
            # 使用残差模块
            # 输入输出都是256*64*64
            for _ in range(n_residual_blocks): # 默认添加9个残差模块
                model += [ResidualBlock(in_features)]
    
            # 进行上采样
            # 第一个range:输入是256*64*64,输出是128*128*128
            # 第二个range:输入是128*128*128,输出是64*256*256       
            out_features = in_features//2
            for _ in range(2):
                model += [  nn.ConvTranspose2d(in_features, out_features, 3, stride=2, padding=1, output_padding=1),
                            nn.InstanceNorm2d(out_features),
                            nn.ReLU(inplace=True) ]
                in_features = out_features
                out_features = in_features//2
    
            # 最后输出层
            # 输入是64*256*256
            # 输出是3*256*256
            model += [  nn.ReflectionPad2d(3),
                        nn.Conv2d(64, output_nc, 7),
                        nn.Tanh() ]
    
            self.model = nn.Sequential(*model)
    
        def forward(self, x):
            return self.model(x)
    

    生成器的结构就是最初那幅图中的右侧的样子。进行下采样之后接一个残差模块,再之后进行上采样。生成器期望可以学到比较复杂的特征构造方法,所以网络结构更深,更复杂。判别器结构相对来说要简单很多。

    3. 判别器

    class Discriminator(nn.Module):
        def __init__(self, input_nc):
            super(Discriminator, self).__init__()
    
            # 构建卷积分类器
            # 输入为3*256*256
            # 输出为64*128*128
            model = [   nn.Conv2d(input_nc, 64, 4, stride=2, padding=1),
                        nn.LeakyReLU(0.2, inplace=True) ]
    
            # 输入为64*128*128
            # 输出为128*64*64
            model += [  nn.Conv2d(64, 128, 4, stride=2, padding=1),
                        nn.InstanceNorm2d(128), 
                        nn.LeakyReLU(0.2, inplace=True) ]
     
            # 输入为128*64*64
            # 输出为256*32*32
            model += [  nn.Conv2d(128, 256, 4, stride=2, padding=1),
                        nn.InstanceNorm2d(256), 
                        nn.LeakyReLU(0.2, inplace=True) ]
    
            # 输入为256*32*32
            # 输出为512*31*31
            model += [  nn.Conv2d(256, 512, 4, padding=1),
                        nn.InstanceNorm2d(512), 
                        nn.LeakyReLU(0.2, inplace=True) ]
    
            # 全卷积分类层
            # 输入为输出为512*31*31
            # 输出为1*30*30
            model += [nn.Conv2d(512, 1, 4, padding=1)]
    
            self.model = nn.Sequential(*model)
    
        def forward(self, x):
            x =  self.model(x)
            # 使用平均池化的办法输出预测值
            # avg_pool2d(input,kernel_size),这里kernel_size为30
            return F.avg_pool2d(x, x.size()[2:]).view(x.size()[0], -1)
    

    就是一个比较普通的分类网络。通过步长为2来逐步缩小尺寸。可能值得注意的是,相比于传统的分类神经网络。我们这里使用全局平均池化的方式进行最终输出预测。没有使用全连接层,减小了网络尺寸。

    此外,我还做了一个exe交互程序。可以直接运行,实现图片中头像识别和对应性别转换。可以体验一下生成对抗网络的趣味。

    在这里插入图片描述

    对网络感兴趣,以及想要详细了解原理是具体如何用代码实现,或者想用有趣数据集做出创意应用的功能的话,可以参考这个视频课程:点击链接

    展开全文
  • 深度有趣 | 20 CycleGAN性别转换

    千次阅读 2018-09-20 10:22:53
    介绍可用于实现多种非配对图像翻译任务的CycleGAN模型,并完成性别转换任务 原理 和pix2pix不同,CycleGAN不需要严格配对的图片,只需要两类(domain)即可,例如一个文件夹都是苹果图片,另一个文件夹都是橘子图片 ...

    简介

    介绍可用于实现多种非配对图像翻译任务的CycleGAN模型,并完成性别转换任务

    原理

    和pix2pix不同,CycleGAN不需要严格配对的图片,只需要两类(domain)即可,例如一个文件夹都是苹果图片,另一个文件夹都是橘子图片

    使用A和B两类图片,就可以实现A到B的翻译和B到A的翻译

    论文官方网站上提供了详细的例子和介绍,https://junyanz.github.io/CycleGAN/,例如苹果和橘子、马和斑马、夏天和冬天、照片和艺术作品等

    CycleGAN非配对图像翻译示例

    以及论文的官方Github项目,https://github.com/junyanz/CycleGAN,使用PyTorch实现

    CycleGAN由两个生成器G和F,以及两个判别器Dx和Dy组成

    CycleGAN模型结构

    G接受真的X并输出假的Y,即完成X到Y的翻译;F接受真的Y并输出假的X,即完成Y到X的翻译;Dx接受真假X并进行判别,Dy接受真假Y并进行判别

    CycleGAN的损失函数和标准GAN差不多,只是写两套而已

    L G A N ( G , D Y , X , Y ) = E y ∼ p y [ log ⁡ D Y ( y ) ] + E x ∼ p x [ log ⁡ ( 1 − D Y ( G ( x ) ) ) ] L_{GAN}(G,D_Y,X,Y)=\mathbb{E}_{y\sim p_y}[\log D_Y(y)]+\mathbb{E}_{x\sim p_x}[\log(1-D_Y(G(x)))] LGAN(G,DY,X,Y)=Eypy[logDY(y)]+Expx[log(1DY(G(x)))]

    L G A N ( F , D X , Y , X ) = E x ∼ p x [ log ⁡ D X ( x ) ] + E y ∼ p y [ log ⁡ ( 1 − D X ( F ( y ) ) ) ] L_{GAN}(F,D_X,Y,X)=\mathbb{E}_{x\sim p_x}[\log D_X(x)]+\mathbb{E}_{y\sim p_y}[\log(1-D_X(F(y)))] LGAN(F,DX,Y,X)=Expx[logDX(x)]+Eypy[log(1DX(F(y)))]

    除此之外,为了避免mode collasp问题,CycleGAN还考虑了循环一致损失(Cycle Consistency Loss)

    L c y c ( G , F ) = E x ∼ p x [ ∥ F ( G ( x ) ) − x ∥ 1 ] + E y ∼ p y [ ∥ G ( F ( y ) ) − y ∥ 1 ] L_{cyc}(G,F)=\mathbb{E}_{x\sim p_x}[\left \| F(G(x))-x \right \|_1]+\mathbb{E}_{y\sim p_y}[\left \| G(F(y))-y \right \|_1] Lcyc(G,F)=Expx[F(G(x))x1]+Eypy[G(F(y))y1]

    因此CycleGAN的总损失如下,G、F、Dx、Dy分别需要min、max其中的部分损失项

    L ( G , F , D X , D Y ) = L G A N ( G , D Y , X , Y ) + L G A N ( F , D X , Y , X ) + λ L c y c ( G , F ) L(G,F,D_X,D_Y)=L_{GAN}(G,D_Y,X,Y)+L_{GAN}(F,D_X,Y,X)+\lambda L_{cyc}(G,F) L(G,F,DX,DY)=LGAN(G,DY,X,Y)+LGAN(F,DX,Y,X)+λLcyc(G,F)

    实现

    在论文的具体实现中,使用了两个tricks

    • 使用Least-Square Loss即最小平方误差代替标准的GAN损失
    • 以G为例,维护一个历史假Y图片集合,例如50张。每次G生成假Y之后将其加到集合中,再从集合中随机地取出一张假Y,和一张真Y一起输入给判别器进行判别。这样一来,假Y集合代表了G根据X生成Y的平均能力,使得训练更加稳定

    使用以下项目训练CycleGAN模型,https://github.com/vanhuyz/CycleGAN-TensorFlow,主要包括几个代码:

    • build_data.py:将图片数据整理为tfrecords文件
    • ops.py:定义了一些小的网络模块
    • generator.py:生成器的定义
    • discriminator.py:判别器的定义
    • model.py:使用生成器和判别器定义CycleGAN
    • train.py:训练模型的代码
    • export_graph.py:将训练好的模型打包成.pd文件
    • inference.py:使用打包好的.pb文件翻译图片,即使用模型进行推断

    生成器和判别器结构如下,如果感兴趣可以进一步阅读项目源码

    CycleGAN模型细节

    性别转换

    使用CelebA中的男性图片和女性图片,训练一个实现性别转换的CycleGAN

    将CelebA数据集中的图片处理成256*256大小,并按照性别保存至male和female两个文件夹,分别包含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
    

    训练开始后,会生成checkpoints文件夹,并根据当前日期和时间生成一个子文件夹,例如20180507-0231,其中包括用于显示tensorboard的events.out.tfevents文件,以及和模型相关的一些文件

    使用tensorboard查看模型训练细节,运行以下命令后访问6006端口即可

    tensorboard --logdir=checkpoints/20180507-0231
    

    以下是迭代185870次之后,tensorboard的IMAGES页面

    CycleGAN模型训练tensorboard细节

    模型训练没有迭代次数限制,所以感觉效果不错或者迭代次数差不多了,便可以终止训练

    使用export_graph.py将模型打包成.pb文件,生成的文件在pretrained文件夹中

    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性别转换结果

    视频性别转换

    对一段视频,识别每一帧可能包含的人脸,检测人脸对应的性别,并使用CycleGAN完成性别的双向转换

    使用以下项目实现性别的检测,https://github.com/yu4u/age-gender-estimation,通过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则下载并安装,http://www.ffmpeg.org/download.html

    进入命令行,从原始视频中提取音频

    ffmpeg -i friends.mp4 -f mp3 -vn sound.mp3
    

    将提取的音频和生成的视频合成在一起

    ffmpeg -i output.mp4 -i sound.mp3 combine.mp4
    

    其他

    项目还提供了四个训练好的模型,https://github.com/vanhuyz/CycleGAN-TensorFlow/releases,包括苹果到橘子、橘子到苹果、马到斑马、斑马到马,如果感兴趣可以尝试一下

    用CycleGAN不仅可以完成两类图片之间的转换,也可以实现两个物体之间的转换,例如将一个人翻译成另一个人

    可以考虑从一部电影中提取出两个角色对应的图片,训练CycleGAN之后,即可将一个人翻译成另一个人

    还有一些比较大胆的尝试,提高驾驶技术:用GAN去除(爱情)动作片中的马赛克和衣服

    参考

    视频讲解课程

    深度有趣(一)

    展开全文
  • EasyExcel自定义Converter解决性别转换问题

    万次阅读 多人点赞 2020-04-28 11:26:51
    那么这篇文章继续介绍一下性别转换的问题,一般我们代码中都会使用**1/0 分别代表 男/女,可是Excel中都是用"男","女"表示的,怎么做才能单独将性别转化为1和0**呢?没错还是自定义转换器! 因为这个案例有...

    上篇文章已经介绍了自定义LocalDateTime转换器解决了LocalDateTime导入导出的问题!

    那么这篇文章继续介绍一下性别转换的问题,一般我们代码中都会使用 1/0 分别代表 男/女 ,可是Excel中都是用"男","女"表示的,怎么做才能 单独将性别转化为1和0 呢?没错还是自定义转换器!
    因为这个案例有LocalDateTime,所以请查看上篇文章采取任意一种解决方案,建议采用第二种:


    新建User类,然后在类上添加EasyExcel的注解

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
    	@ExcelProperty(value = "姓名", index = 0)
    	private String name;
    	@ExcelProperty(value = "年龄", index = 1)
    	private Integer age;
        // 1 男   0 女
    	@ExcelProperty(value = "性别", index = 2)
    	private Integer sex;
    	@ExcelProperty(value = "创建时间", index = 3)
    	private LocalDateTime createTime;
    }
    

    新建Controller用于测试

    @Slf4j
    @RestController
    public class ExcelController {
    
    	@PostMapping("/importData")
    	public void importData(@RequestParam("file") MultipartFile file) throws IOException {
    		if (file == null) return;
    		ArrayList<Object> list = new ArrayList<>();
    		AnalysisEventListener listener = new AnalysisEventListener() {
    			@Override
    			public void invoke(Object data, AnalysisContext context) {
    				list.add(data);
    			}
    
    			@Override
    			public void doAfterAllAnalysed(AnalysisContext context) {
    				log.info("导入数据完毕");
    			}
    		};
    		try {
    			EasyExcel.read(file.getInputStream(), User.class, listener).sheet(0).doRead();
    		} catch (IOException e) {
    			log.error("导入出错:{}", e.getMessage());
    		}
    		list.forEach(System.out::println);
    	}
    
    	@PostMapping("/exportData")
    	public void exportData(HttpServletResponse response) {
    		List<User> list = getList();
    		try {
    			response.setContentType("application/vnd.ms-excel; charset=utf-8");
    			response.setCharacterEncoding("utf-8");
    			String fileName = "三好学生表";
    			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8") + ".xlsx");
    			EasyExcel.write(response.getOutputStream(), User.class).registerConverter(new LocalDateTimeConverter()).sheet("test").doWrite(list);
    		} catch (Exception e) {
    			log.error("下载报表异常:{}", e.getMessage());
    			throw new RuntimeException("下载报表异常");
    		}
    	}
    
    	private List<User> getList() {
    		List<User> list = new ArrayList<>();
    		LocalDateTime now = LocalDateTime.now();
    		User xd = new User("熊大", 10, 1, now);
    		User ne = new User("牛二", 20, 0, now);
    		User zs = new User("张三", 30, 1, now);
    		User ls = new User("李四", 40, 1, now);
    		User ww = new User("王五", 50, 0, now);
    		list.add(xd);
    		list.add(ne);
    		list.add(zs);
    		list.add(ls);
    		list.add(ww);
    		return list;
    	}
    }
    

    访问exportData接口会发现不是我们想要的结果:为什么导出的文件性别那一列只有0 1 没有男 女呢?好吧!那我们就自定义转换器,因为我们要转换0和1即Integer,所以编写如下转换器!注意要实现的是com.alibaba.excel.converters.Converter接口,别引用错包了!

    public class SexConverter implements Converter<Integer> {
    	@Override
    	public Class supportJavaTypeKey() {
    		return Integer.class;
    	}
    
    	@Override
    	public CellDataTypeEnum supportExcelTypeKey() {
    		return CellDataTypeEnum.STRING;
    	}
    
    	@Override
    	public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
    		return "男".equals(cellData.getStringValue()) ? 1 : 0;
    	}
    
    	@Override
    	public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
    		return new CellData(value.equals(1) ? "男" : "女");
    	}
    }
    

    划重点!Sex的converter编写完了,怎么才能让它生效呢?有一种解决方案!

    1. 找到需要转换的字段,在@ExcelProperty上添加converter属性

    修改代码完毕之后再重启就可以了,不管是导入还是导出都没问题!Excel中的男/女导入之后在代码中会自动变为1/0,代码中的1/0导出之后会自动变为男/女!赶快试试吧!

    细心的小伙伴已经发现了,LocalDateTime的converter有三种生效方案,但是sex的converter只有一种!点击查看Converter使用总结并带你追踪一下源码并给出具体的解决方案!

    加油!

    展开全文
  • 2019独角兽企业重金招聘Python工程师标准>>> select decode(性别,'男',1,2) from 表名 转载于:https://my.oschina.net/u/2336787/blog/414176
    select decode(性别,'男',1,2) from 表名

    转载于:https://my.oschina.net/u/2336787/blog/414176

    展开全文
  • 最近,Snapchat推出了一款可以改变性别的滤镜,不用再化妆换衣服戴假发,只需要一键就能实现性别转换。类似滤镜其实已经有很多,但是snapchat这款新品非常真实,保持了用户原有的颜值特征,并且变装效果非常真实。...
  • 深度学习项目将男性画像转换成女性,反之亦然
  • SELECT CASE(字段) WHEN 1 then '是' ELSE '否' END AS 字段 FROM 表
  • 开发项目的过程中,经常会碰到这样的问题:学生信息管理系统中,学生的专业、性别字段,底层...我们将数据库中的性别信息取出来,在前台jsp页面通过JS或者JQuery来处理和转换:JSP页面:性别要求required="require...
  • 配置性别枚举转换

    2019-10-16 21:09:47
    数据库性别存入0(女),1(男) 返回显示男女 @Getter public enum Gender { MALE(0, "男"), FEMALE(1, "女"); Gender(int code, String desc) { this.code = code; this.desc = desc; } //配置枚举...
  • 性别转换的查询语句

    2007-10-14 21:02:00
    select a= case sex when 1 then 男 when 0 then 女 else 中 end from users 
  • VUE 性别选择

    千次阅读 2019-10-31 10:33:50
    <view class="groupSex"> <view v-for="(item,index) in sexList" class="radios" :class="{radiosChecked:active == index}" @click="chooseSex(index)">{{item}}</view> <...
  • 通用写法 SELECT id, username, age, (CASE WHEN SEX = 1 THEN '男' WHEN SEX = 2 THEN '女' ELSE '未知' END) 'sex' FROM t_user u WHERE u.id in (1,2,3) SELECT USER_A...
  • agenderpred 使用Tensorflow的年龄和性别预测因子
  • MySQL如使用SQL语句交换男女性别

    千次阅读 2019-04-20 20:51:37
    1.应用场景 ... 2.1如何使用SQL语句交换男女性别[只使用一条update语句] //默写两遍才把方式一书写下来! 方式一: update user set sex = case sex when '男' then '女' else '男' end; ...
  • java 利用opencv实现图片的类型转换

    千次阅读 2021-11-07 16:05:05
    java 利用opencv实现图片的类型转换 1.导入jar 和opencv的dll 运行库 链接: https://pan.baidu.com/s/1TBPXLV_xAhP4EpercV0enQ 提取码: qb1k (这个网盘是我的>---<) 里面以jar和运行库 2.代码展示 代码两行...
  • elementUI中对table数据显示进行转换

    千次阅读 2021-01-08 19:20:05
    在项目中需要用到数据转换,如:性别,0为男性,1为女性,存在数据库中的数据为0或1,那么我们需要使用 :formatter 来进行数据转换。 列表界面 以下附上代码: // 列表column <el-table-column label="性别" ...
  • prop中字段数据进行三元运算 0 1 2 转换为 女 男 未知
  • 知乎介绍:图像转换明星StarGAN,这次有了简易版TensorFlow实现 starGAN性别反转原始代码(github):PyTorch Implementation of StarGAN - CVPR 2018 starGAN性别反转简易demo(github):Simple Tensorflow ...
  • Python中将非数值的类别转换为数字

    千次阅读 2018-12-29 12:08:10
    在我们对数值数据进行处理时,如果遇到数据中非数值的类别可以采用将其转换为数字的形式,我们采用sklearn中的LabelEncoder 比如UCI中的Letter数据集,类别有26类,我们可以采用以下简单方法将类别直接转换为0~25的...
  • 微信小程序之性别单选效果

    千次阅读 2020-06-17 11:46:49
    效果图: 代码: ... <view class="inputbox">...性别</view> <view class="inpbox"> <radio-group bindchange="radioChange" class="inp radiogroup"> <view class="radiobox" wx:for
  • 在将数据放入表格中进行列表展示时不可避免的需要进行类似于字典码转换的工作,比如说数据库中user表中的性别属性,表中为了读取操作的便利一般用0,1来代替女,男这两个字符,但是数据到打前台后必须要进行转换显示...
  • } } 在convertToExcelData()方法里面写将数据库字段转换成EXCEL显示字段的逻辑,如: @Override public CellData convertToExcelData(Integer integer, ExcelContentProperty excelContentProperty, Global...
  • java实现数据的Excel导出, 自定义导出字段, 转换字典值 第一版代码: 基础功能跳转此文章java自定义Excel导出工具: 简介 新增功能: 添加自定义字段导出功能, 用户可以选择字段进行导出 将字典类型数据进行转换(如:0=...
  • vue实现性别选择框

    千次阅读 2019-04-09 15:49:05
    这篇文章主要是简单的实现了vue2.0移动端自定义性别选择的功能,很简单但是经常用到,于是写了一个小小的demo,记录下来。 效果图: 图片.png 实现代码: <template> <div class="app"> &...
  • SQLserver总结(COUNT(*)、类型转换函数、联合UNION) use wx105;create table sale(proName nvarchar(100),sales int);insert into sale values('傻子瓜子',30);insert into sale values('青岛啤酒',20);insert into...
  • js捆绑html语句时如 转换对(0=女 1=男) 类型的替换写法
  • Java使用poi做加自定义注解实现对象与Excel相互转换

    千次阅读 多人点赞 2021-05-27 09:31:25
    /** * 将对象转换成Excel * * @param objList 需要转换的对象 * @return 返回是poi中的对象 */ public static HSSFWorkbook toExcel(List objList) { if (CollectionUtils.isEmpty(objList)) throw new ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 77,323
精华内容 30,929
关键字:

性别转换