此前Zoom的安全漏洞引发了全球关注,15000个视频被公开到网上,造成视频中的个人信息泄漏,虽然Zoom采取了很多安全举措来修补漏洞,但由于产品本身的设计缺陷,修复所有问题远非一日之功。在此期间,如何通过自己的设置,来保障信息安全呢?
近日,一位开发者在GitHub开源了自己的解决方案avatarify,为Zoom、Skype这类视频通话应用添加自己的替身。
让马斯克加入你的Zoom会议
哇哦,马斯克加入了我们的群聊!
7
当然这并不是真的马斯克。你可能会问这跟DeepFake有啥区别?我们知道DeepFake的训练和推理速度是非常慢的,满足不了视频通话的实时性要求,这个项目大大缩短了时间延迟,而且不需要大量的替身图片信息,一张就够!
项目核心组件:一阶运动模型
avatarify项目站在了巨人的肩膀上,项目中使用的一个核心模型first order model来源于下面这篇NIPS论文。
这个模型可以根据驱动视频的运动,对源图像中的对象进行动画处理,以生成视频序列,而无需使用任何注释或有关特定对象的先验信息。
模型采用自监督的方法将外观和运动信息分离,使用了视频中对象的关键点及其局部仿射变换进行特征表示。生成器网络对目标运动期间出现的遮挡进行建模,并将源图像中提取的外观与从驱动视频获得的运动进行组合。
可以看出模型由两个主要模块组成:运动估计模块和图像生成模块。
运动估计模块的目的是预测密集的运动场。我们假设存在一个抽象的参考框架,然后独立地估计了两种转换:从参考到源以及从参考到驱动,这样的设计使模型能够独立处理源帧和驱动帧。
我们可以使用这个模型轻松地将特朗普的讲话迁移到权游中的人物,也可以让形态相似的静态马奔跑起来,还能一键完成模特的换装,对需要制作大量换装图片的美工来说简直是神器!
来,让Lecun模仿下Hinton。
对比下FaceSwap的效果,高下立判。
还有一个比较重要的操作就是人脸对齐,作者使用了另一个开源项目face_alignment来提取人脸关键点。
如何在Zoom会议中使用替身
有了这两个核心组件,我们就可以来实现视频中的替身制作了,来看下完成替身生成的几个关键操作。
加载训练好的模型
def load_checkpoints(config_path, checkpoint_path, device='cuda'): with open(config_path) as f: config = yaml.load(f) generator = OcclusionAwareGenerator(**config['model_params']['generator_params'], **config['model_params']['common_params']) generator.to(device) kp_detector = KPDetector(**config['model_params']['kp_detector_params'], **config['model_params']['common_params']) kp_detector.to(device) checkpoint = torch.load(checkpoint_path, map_location=device) generator.load_state_dict(checkpoint['generator']) kp_detector.load_state_dict(checkpoint['kp_detector']) generator = DataParallelWithCallback(generator) kp_detector = DataParallelWithCallback(kp_detector) generator.eval() kp_detector.eval() return generator, kp_detector
关键点的归一化
def normalize_alignment_kp(kp): kp = kp - kp.mean(axis=0, keepdims=True) area = ConvexHull(kp[:, :2]).volume area = np.sqrt(area) kp[:, :2] = kp[:, :2] / area return kp
图片的剪裁和扩展
def crop(img, p=0.7): h, w = img.shape[:2] x = int(min(w, h) * p) l = (w - x) // 2 r = w - l u = (h - x) // 2 d = h - u return img[u:d, l:r], (l,r,u,d) def pad_img(img, orig): h, w = orig.shape[:2] pad = int(256 * (w / h) - 256) out = np.pad(img, [[0,0], [pad//2, pad//2], [0,0]], 'constant') out = cv2.resize(out, (w, h)) return out
预测图片生成
def predict(driving_frame, source_image, relative, adapt_movement_scale, fa, device='cuda'): global start_frame global start_frame_kp global kp_driving_initial with torch.no_grad(): source = torch.tensor(source_image[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2).to(device) driving = torch.tensor(driving_frame[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2).to(device) kp_source = kp_detector(source) if kp_driving_initial is None: kp_driving_initial = kp_detector(driving) start_frame = driving_frame.copy() start_frame_kp = get_frame_kp(fa, driving_frame) kp_driving = kp_detector(driving) kp_norm = normalize_kp(kp_source=kp_source, kp_driving=kp_driving, kp_driving_initial=kp_driving_initial, use_relative_movement=relative, use_relative_jacobian=relative, adapt_movement_scale=adapt_movement_scale) out = generator(source, kp_source=kp_source, kp_driving=kp_norm) out = np.transpose(out['prediction'].data.cpu().numpy(), [0, 2, 3, 1])[0] out = out[..., ::-1] out = (np.clip(out, 0, 1) * 255).astype(np.uint8) return out
完成了这几步,在Zoom中设置摄像头使用avatarify,就可以将生成的图像通过OpenCV实时推送到视频流了。建议使用头像缩放功能,使你的脸在预览窗口中的比例和位置尽可能接近替身头像。对齐后,点击 X 来使用这个帧作为参考帧,驱动视频的生成。
将你想用的替身图片(通过快捷键1-9还可以实时更换)放在avatars文件夹下就能实现该功能了,赶紧去给你的Zoom添加个替身吧,再也不用担心隐私泄漏了!
参考链接:
http://papers.nips.cc/paper/8935-first-order-motion-model-for-image-animation
https://aliaksandrsiarohin.github.io/first-order-model-website/