视差图像—— 了解 2D 图像新方法

https://miro.medium.com/max/1200/1*T2UzD6ZjHrkmCaJzcSSd7g.gif
视差图像演示图片网址

我们都看过 3D 电影、幻觉图像,并且了解制作它们的诀窍。这让我想到了制作一些工具,这些工具能使图像随着用户头部移动而改变视角。光是想想就能知道它有多酷。

会有什么效果?

视差 这个术语我们都知道,它是物体表观位置的变化量,而变化量取决于我们离它的距离。


视差

因此,如果我们能在二维图像中获得同样的图像的不同层次以不同的方式移动的效果,那么我们就能让这些图像有更明显的景深,达到我们想要的酷炫效果。

分解过程

1_YRE9NHt8zeeUpyj3KVztqA
深度图

首先,我们需要将图像分成不同的层,为此我们需要一个 2D 图像的深度图。 深度图 是一个简单的黑白图像,其中图像的白度告诉对象的接近程度POV。获得基本图层后,我们需要对每一层中缺失的部分进行 修补 。所以最后,我们将单个图像分解为不同的层。现在我们可以在彼此之上显示不同的图层,它们看起来与原始图像相同。现在我们可以使用我们的相机进行人 脸检测 并测量用户头部的运动,然后移动这些层以匹配新的 POV。

如何编码这个工具

首先,我们需要导入一些文件,因此将此代码复制到文件中。

我推荐使用4.1.0.25版本的OpenCV,因为我们在使用face_cascade时在以后的版本中很少有bug。对于其他库,你可以使用任何版本,但最好使用较新的库。

import os, sys
import numpy as np
import pygame as pg
import cv2

现在我们需要加载图像和 深度图 并调整它们的大小以匹配大小。现在,我们将为我们的代码提供深度图,但你可以使用我在主要工具中使用的模型 MiDaS 生成的深度图。你可以看看我的 GitHub repo

现在,在我们加载了深度图后,我们可以通过在不同阈值下对深度图进行阈值处理来为不同层创建掩码。

img = cv2.imread('moon.jpg', flags=cv2.CV_8UC4)
depth_map = cv2.imread('moon_depth_map.png')
depth_map = cv2.cvtColor(depth_map,cv2.COLOR_RGB2GRAY)
img = cv2.resize(img, depth_map.shape[:2])

%E6%9C%AA%E5%91%BD%E5%90%8D_%E5%89%AF%E6%9C%AC 1_-Zq9r6gFsPzSeogDv6W4hA
在制作一层时,我们需要两个蒙版,一个是这一层,另一个是前一层的第二个来修复缺失的部分。我们将把最后一层放在循环之外,这样我们就可以提取这一层中的所有剩余部分。

我们已经颠倒了图层,因此我们可以按照从 最后到第一层的 顺序排列它们。当我们将图层添加到列表中时,我们使用了一个函数“ conv_cv_alpha ”,这将添加 alpha 值 (使 RGB 为 RGBA) 并使用蒙版使图层的部分透明。

def conv_cv_alpha(cv_image, mask):    
    b, g, r = cv2.split(cv_image)    
    rgba = [r, g, b, mask]    
    cv_image = cv2.merge(rgba,4)    
          
    return cv_image

现在是人脸检测和显示图像的部分。对于人脸检测,我们将使用 haarcascade 。从他们的官方Github 存储库下载它们。

要下载它们,请右键单击“原始”=>“将链接另存为”。确保它们在你的工作目录中。

现在我们将加载用于人脸检测的 haar 级联并创建一个函数,该函数将从图像中返回 face-rect。

face_cascade = cv2.CascadeClassifier( 'haarcascade_frontalface_default.xml')   

def get_face_rect(img):    
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    
    face_rects = face_cascade.detectMultiScale(gray_img, 1.3, 5)
    if len(face_rects) == 0:         
        return ()
    return face_rects[0]

现在我们必须显示将根据用户的头部移动的图像。我们将使用 OpenCV 读取 cam,然后使用 Pygame 来渲染每一帧。为了计算每一层的位移,我们将计算头部从帧中心的位移,然后将其缩小以获得一个小的位移值。之后,我们将每层的索引值相乘以获得相应层的移位值,您也可以在其中乘以一些常数值以获得更好的结果。

我们将创建一个比原始图像稍小的 Pygame 窗口并加载相机。这里使用了 scale ,因此你可以更改其值以使最终产生更大的结果。

scale = 1
off_set = 20
width, height = layers[0].get_width(), layers[0].get_height()        win = pg.display.set_mode((int((width - off_set)*scale), int((height - off_set)*scale)))    
pg.display.set_caption('Parallax_image')
scaled_layers = []    
for layer in layers: 
             scaled_layers.append(pg.transform.scale(layer, (int(width*scale), int(height*scale))))
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

我们将设置一些常量。你可以使用这些常量来获得不同的结果。

x_transform = True     # allow shift in x-axis
y_transform = False    # allow shift in y-axis
sens = 50              # the amount of scale down of shift value
show_cam = False       # show your face cam
shift_x = 0    
shift_y = 0    
run = True

最后,主循环渲染所有图层。


image
就是这样,最后的结果如下。
https://miro.medium.com/max/863/1H6L0UFuTpWzD_IB0EFqSvg.gif
最终结果图片网址
https://miro.medium.com/max/863/1
24XN55FuLp0IKIa3PQefPw.gif
不同图片演示

我已经创建了这个工具的更高级版本,你可以在其中选择图像,它会自动创建视差图像,将自动生成深度图。

你可以在我的 GitHub 存储 库中查看更多信息。

原文作者 Striker
原文链接 https://medium.com/analytics-vidhya/parallax-images-14e92ebb1bae