大家好,关于girlfriend漫画很多朋友都还不太明白,今天小编就来为大家分享关于制作漫画风头像的知识,希望对各位有所帮助!
本文分享自华为云社区《AnimeGANv2照片动漫化:如何基于PyTorch和神经网络给GirlFriend制作漫画风头像?【秋招特训】-云社区-华为云》,作者:白鹿第一帅。
将现实世界场景的照片转换为动漫风格图像的方法,这是计算机视觉和艺术风格转换中一项有意义且具有挑战性的任务,而本文中我们介绍的AnimeGAN就是GitHub上一款爆火的二次元漫画风格迁移工具,可以实现快速的动画风格迁移。该工具是基于神经风格迁移和生成对抗网络(GAN)技术打造的,相比于传统的神经网络模型,GAN是一种全新的非监督式的架构。最近AnimeGAN发布了其二代版本,据称更新后AnimeGANv2支持了风景照片和风景视频的三种动漫化风格(分别是宫崎骏、新海诚和金敏),视觉效果更佳,模型体量也更小且容易训练了。
通过三种新颖的损失函数,使生成的图像具有更好的动画视觉效果,这些损失函数是灰度样式损失、灰度对抗损失和颜色重建损失。AnimeGAN可以很容易地使用未配对的训练数据进行端到端训练。
实现原理可以参考原论文:https://link.springer.com/chapter/10.1007/978-981-15-5577-0_18,具体如下图所示:
AnimeGANv2是照片漫画工具AnimeGAN的升级版本,AnimeGANv2在训练AI时GAN包括了两套独立的网络A和B,A网络是需要训练的分类器,用来分辨成图是否符合标准;B网络是生成器,生成类似于真实样本的随机样本,并将其作为假样本以欺骗网络A。在A和B的对抗中,AI的水平逐渐提升,最后实现质的飞跃,相较于之前版本,AnimeGANv2主要在以下四个方面进行优化:
AnimeGANv2可以将现实场景的图片处理为动漫画风,目前支持宫崎骏、新海诚和今敏的三种风格,三者实现效果具体如下图所示:
Github地址:https://github.com/TachibanaYoshino/AnimeGANv2,详情具体如下图所示:
我们将本次案例中的相关代码和数据存放于华为云提供的对象存储服务OBS中,推荐大家使用:https://www.huaweicloud.com/product/obs.html,产品详细信息具体如下图所示:
对象存储服务(ObjectStorageService,OBS)提供海量、安全、高可靠、低成本的数据存储能力,可供用户存储任意类型和大小的数据。适合企业备份/归档、视频点播、视频监控等多种数据存储场景,在我本人的使用以及测试中对象存储服务OBS效果颇好,故推荐给大家使用,具体如下图所示:
本次案例运行的实验平台为华为云的AI开发平台ModelArts,详细信息请点击:https://support.huaweicloud.com/modelarts/index.html,产品详细信息具体如下图所示:
ModelArts是面向开发者的一站式AI开发平台,为机器学习与深度学习提供海量数据预处理及半自动化标注、大规模分布式Training、自动化模型生成,及端-边-云模型按需部署能力,帮助用户快速创建和部署模型,管理全周期AI工作流,在我本人的使用以及测试中ModelArts效果颇好且提供了可以满足不同开发需求的运行环境(部分免费),故推荐给大家使用,具体如下图所示:
可以在华为云AI开发平台ModelArts提供的JupyterLab中选择不同的实验环境内核,具体如下图所示:
获取代码和数据,相关实现命令如下所示:
importosn!wgethttps://obs-aigallery-zc.obs.cn-north-4.myhuaweicloud.com/clf/code/AnimeGAN/AnimeGAN.zipnos.system('unzipAnimeGAN.zip')n
我们可以在华为云AI开发平台ModelArts提供的JupyterLab查看具体运行过程和结果,具体如下图所示:
安装依赖库,相关实现命令如下所示:
!pipinstalldlibn!pipuninstall-ytorchn!pipuninstall-ytorchvisionn!pipinstalltorchn!pipinstalltorchvisionn%cdAnimeGANv2n
我们可以在华为云AI开发平台ModelArts提供的JupyterLab查看具体运行过程和结果,具体如下图所示:
说明:由于运行结果过于冗长,仅截取首端与末端运行结果。
##AnimeGANv2源码解析nnimportosnimportdlibnimportcollectionsnfromtypingimportUnion,ListnimportnumpyasnpnfromPILimportImagenimportmatplotlib.pyplotaspltndefget_dlib_face_detector(predictor_path:str="shape_predictor_68_face_landmarks.dat"):nnifnotos.path.isfile(predictor_path):nmodel_file="shape_predictor_68_face_landmarks.dat.bz2"nos.system(f"wgethttp://dlib.net/files/{model_file}")nos.system(f"bzip2-dk{model_file}")nndetector=dlib.get_frontal_face_detector()nshape_predictor=dlib.shape_predictor(predictor_path)nndefdetect_face_landmarks(img:Union[Image.Image,np.ndarray]):nifisinstance(img,Image.Image):nimg=np.array(img)nfaces=[]ndets=detector(img)nfordindets:nshape=shape_predictor(img,d)nfaces.append(np.array([[v.x,v.y]forvinshape.parts()]))nreturnfacesnnreturndetect_face_landmarksndefdisplay_facial_landmarks(nimg:Image,nlandmarks:List[np.ndarray],nfig_size=[15,15]n):nplot_style=dict(nmarker='o',nmarkersize=4,nlinestyle='-',nlw=2n)npred_type=collections.namedtuple('prediction_type',['slice','color'])npred_types={n'face':pred_type(slice(0,17),(0.682,0.780,0.909,0.5)),n'eyebrow1':pred_type(slice(17,22),(1.0,0.498,0.055,0.4)),n'eyebrow2':pred_type(slice(22,27),(1.0,0.498,0.055,0.4)),n'nose':pred_type(slice(27,31),(0.345,0.239,0.443,0.4)),n'nostril':pred_type(slice(31,36),(0.345,0.239,0.443,0.4)),n'eye1':pred_type(slice(36,42),(0.596,0.875,0.541,0.3)),n'eye2':pred_type(slice(42,48),(0.596,0.875,0.541,0.3)),n'lips':pred_type(slice(48,60),(0.596,0.875,0.541,0.3)),n'teeth':pred_type(slice(60,68),(0.596,0.875,0.541,0.4))n}nnfig=plt.figure(figsize=fig_size)nax=fig.add_subplot(1,1,1)nax.imshow(img)nax.axis('off')nnforfaceinlandmarks:nforpred_typeinpred_types.values():nax.plot(nface[pred_type.slice,0],nface[pred_type.slice,1],ncolor=pred_type.color,**plot_stylen)nplt.show()n#https://github.com/NVlabs/ffhq-dataset/blob/master/download_ffhq.pynnimportPIL.ImagenimportPIL.ImageFilenimportnumpyasnpnimportscipy.ndimagendefalign_and_crop_face(nimg:Image.Image,nlandmarks:np.ndarray,nexpand:float=1.0,noutput_size:int=1024,ntransform_size:int=4096,nenable_padding:bool=True,n):n#将五官数据转为数组n#pylint:disable=unused-variablenlm=landmarksnlm_chin=lm[0:17]#left-rightnlm_eyebrow_left=lm[17:22]#left-rightnlm_eyebrow_right=lm[22:27]#left-rightnlm_nose=lm[27:31]#top-downnlm_nostrils=lm[31:36]#top-downnlm_eye_left=lm[36:42]#left-clockwisenlm_eye_right=lm[42:48]#left-clockwisenlm_mouth_outer=lm[48:60]#left-clockwisenlm_mouth_inner=lm[60:68]#left-clockwisenn#计算辅助向量neye_left=np.mean(lm_eye_left,axis=0)neye_right=np.mean(lm_eye_right,axis=0)neye_avg=(eye_left+eye_right)*0.5neye_to_eye=eye_right-eye_leftnmouth_left=lm_mouth_outer[0]nmouth_right=lm_mouth_outer[6]nmouth_avg=(mouth_left+mouth_right)*0.5neye_to_mouth=mouth_avg-eye_avgnn#提取矩形框nx=eye_to_eye-np.flipud(eye_to_mouth)*[-1,1]#flipud函数实现矩阵的上下翻转;数组乘法,每行对应位置相乘nx/=np.hypot(*x)nx*=max(np.hypot(*eye_to_eye)*2.0,np.hypot(*eye_to_mouth)*1.8)nx*=expandny=np.flipud(x)*[-1,1]nc=eye_avg+eye_to_mouth*0.1nquad=np.stack([c-x-y,c-x+y,c+x+y,c+x-y])nqsize=np.hypot(*x)*2nn#缩放nshrink=int(np.floor(qsize/output_size*0.5))nifshrink>1:nrsize=(int(np.rint(float(img.size[0])/shrink)),int(np.rint(float(img.size[1])/shrink)))nimg=img.resize(rsize,PIL.Image.ANTIALIAS)nquad/=shrinknqsize/=shrinknn#裁剪nborder=max(int(np.rint(qsize*0.1)),3)ncrop=(int(np.floor(min(quad[:,0]))),int(np.floor(min(quad[:,1]))),int(np.ceil(max(quad[:,0]))),int(np.ceil(max(quad[:,1]))))ncrop=(max(crop[0]-border,0),max(crop[1]-border,0),min(crop[2]+border,img.size[0]),min(crop[3]+border,img.size[1]))nifcrop[2]-crop[0]<img.size[0]orcrop[3]-crop[1]<img.size[1]:nimg=img.crop(crop)nquad-=crop[0:2]nn#填充数据npad=(int(np.floor(min(quad[:,0]))),int(np.floor(min(quad[:,1]))),int(np.ceil(max(quad[:,0]))),int(np.ceil(max(quad[:,1]))))npad=(max(-pad[0]+border,0),max(-pad[1]+border,0),max(pad[2]-img.size[0]+border,0),max(pad[3]-img.size[1]+border,0))nifenable_paddingandmax(pad)>border-4:npad=np.maximum(pad,int(np.rint(qsize*0.3)))nimg=np.pad(np.float32(img),((pad[1],pad[3]),(pad[0],pad[2]),(0,0)),'reflect')nh,w,_=img.shapeny,x,_=np.ogrid[:h,:w,:1]nmask=np.maximum(1.0-np.minimum(np.float32(x)/pad[0],np.float32(w-1-x)/pad[2]),1.0-np.minimum(np.float32(y)/pad[1],np.float32(h-1-y)/pad[3]))nblur=qsize*0.02nimg+=(scipy.ndimage.gaussian_filter(img,[blur,blur,0])-img)*np.clip(mask*3.0+1.0,0.0,1.0)nimg+=(np.median(img,axis=(0,1))-img)*np.clip(mask,0.0,1.0)nimg=PIL.Image.fromarray(np.uint8(np.clip(np.rint(img),0,255)),'RGB')nquad+=pad[:2]nn#转化图片nimg=img.transform((transform_size,transform_size),PIL.Image.QUAD,(quad+0.5).flatten(),PIL.Image.BILINEAR)nifoutput_size<transform_size:nimg=img.resize((output_size,output_size),PIL.Image.ANTIALIAS)nnreturnimgn
#@titleAnimeGANmodelfromhttps://github.com/bryandlee/animegan2-pytorchn#!gitclonehttps://github.com/bryandlee/animegan2-pytorchnnmodel_fname="face_paint_512_v2_0.pt"nn#model_urls={n#"face_paint_512_v0.pt":"https://drive.google.com/uc?id=1WK5Mdt6mwlcsqCZMHkCUSDJxN1UyFi0-",n#"face_paint_512_v2_0.pt":"https://drive.google.com/uc?id=18H3iK09_d54qEDoWIc82SyWB2xun4gjU",n#}nn#!gdown{model_urls[model_fname]}nnimportsysnsys.path.append("animegan2-pytorch")nnimporttorchnntorch.set_grad_enabled(False)nprint(torch.__version__,torch.cuda.is_available())nfrommodelimportGeneratornndevice="cpu"nnmodel=Generator().eval().to(device)nmodel.load_state_dict(torch.load(model_fname))nnfromPILimportImagenfromtorchvision.transforms.functionalimportto_tensor,to_pil_imagenndefface2paint(nimg:Image.Image,nsize:int,nside_by_side:bool=True,n)->Image.Image:nnw,h=img.sizens=min(w,h)nimg=img.crop(((w-s)//2,(h-s)//2,(w+s)//2,(h+s)//2))nimg=img.resize((size,size),Image.LANCZOS)nninput=to_tensor(img).unsqueeze(0)*2-1noutput=model(input.to(device)).cpu()[0]nnifside_by_side:noutput=torch.cat([input[0],output],dim=2)nnoutput=(output*0.5+0.5).clip(0,1)nnreturnto_pil_image(output)n
对应运行结果具体如下:
1.11.0+cu102Truen七、素材应用照片动漫化7.1、通过文件路径获取素材文件
定义一个应用函数,通过文件路径获取素材文件,具体实现代码如下:
definference_from_file(filepath):nimg=Image.open(filepath).convert("RGB")nnface_detector=get_dlib_face_detector()nlandmarks=face_detector(img)nndisplay_facial_landmarks(img,landmarks,fig_size=[5,5])nnforlandmarkinlandmarks:nface=align_and_crop_face(img,landmark,expand=1.3)ndisplay(face2paint(face,512))n
我们分别对命名为“4.jpg”和“1.jpg”的素材照片应用漫画化效果,具体实现代码如下:
inference_from_file('1.jpg')n
inference_from_file('4.jpg')n
对于命名为“1.jpg”的图片分析过程具体如下图所示:
输出结果,我们着重在脸部与原图“1.jpg”进行对比,具体如下图所示:
对于命名为“4.jpg”的图片分析过程具体如下图所示:
输出结果,我们着重在脸部与原图“4.jpg”进行对比,具体如下图所示:
定义一个应用函数,通过URL地址获取素材文件,具体实现代码如下:
importrequestsnndefinference_from_url(url):nimg=Image.open(requests.get(url,stream=True).raw).convert("RGB")nnface_detector=get_dlib_face_detector()nlandmarks=face_detector(img)nndisplay_facial_landmarks(img,landmarks,fig_size=[5,5])nnforlandmarkinlandmarks:nface=align_and_crop_face(img,landmark,expand=1.3)ndisplay(face2paint(face,512))n
我们通过获取URL地址中的素材照片“6.jpg”实现,具体实现代码如下:
inference_from_url("https://obs-aigallery-zc.obs.cn-north-4.myhuaweicloud.com/clf/code/AnimeGAN/6.jpg")n
对于命名为“6.jpg”的图片分析过程具体如下图所示:
输出结果,我们着重在脸部与原图“6.jpg”进行对比,具体如下图所示:
当然也考虑到一些同学因为某些原因无法进行实验环境操作,在这里为大家提供线上AnimeGANv2照片动漫化,感兴趣的同学请点击:https://huggingface.co/spaces/akhaliq/AnimeGANv2,在这里呢就有一些局限性,目前仅支持两个version:
玩一玩,还是够用的!嘿嘿嘿!马斯克?!
不说了,我要去给女朋友整一个!你们看着办,该不会是没有女朋友吧?!
在本文中我们给大家介绍了基于神经风格迁移和生成对抗网络(GAN)技术打造的照片漫画风格迁移工具AnimeGANv2,并通过华为云平台提供的AI开发平台ModelArts进行了效果演示,其中对于AnimeGANv2源码部分以及通过文件路径获取素材文件和通过URL地址获取素材文件两种不同的应用方式进行了重点拆分,这是一种设计模式的体现。通过技术手段在计算机视觉和艺术风格转换方面的应用,实现照片的快速动漫化效果,对于作者来说是一种挑战,那对于我们其他用户来说呢?新领域新机遇?
点击下方,第一时间了解华为云新鲜技术~
华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云
关于girlfriend漫画的内容到此结束,希望对大家有所帮助。