如何用Python制作一个换脸程序

  介绍

小编这次要给大家分享的是如何用Python制作一个换脸程序,文章内容丰富,感兴趣的小伙伴可以来了解一下,希望大家阅读完这篇文章之后能够有所收获。

如何用Python制作一个换脸程序

在这篇文章中我将介绍如何写一个简短(200行)的Python脚本,来自动地将一幅图片的脸替换为另一幅图片的脸。

这个过程分四步:

    <李>检测脸部标记。 <李>旋转,缩放,平移和第二张图片,以配合第一步。 <李>调整第二张图片的色彩平衡,以适配第一张图片。 <李>把第二张图像的特性混合在第一张图像中。

该脚本使用dlib的Python绑定来提取面部标记:

<中心> 如何用Python制作一个换脸程序

dlib实现了瓦希德大使和约瑟芬沙利文的《使用回归树一毫秒脸部对准》论文中的算法。算法本身非常复杂,但dlib接口使用起来非常简单:

 PREDICTOR_PATH=?home/马特/dlib - 18.16/shape_predictor_68_face_landmarks.dat"
  探测器=dlib.get_frontal_face_detector ()
  预测=dlib.shape_predictor (PREDICTOR_PATH)
  def get_landmarks (im):
  矩形=检测器(im, 1)
  如果len(矩形)的在1:
  提高TooManyFaces
  如果len(矩形)==0:
  提高NoFaces
  返回numpy.matrix ([[p。x, p。y)在预测p (im,矩形[0]).parts ())) 

get_landmarks()函数将一个图像转化成numpy数组,并返回一个68×2元素矩阵,输入图像的每个特征点对应每行的一个x, y坐标。

特征提取器(预测)需要一个粗糙的边界框作为算法输入,由一个传统的能返回一个矩形列表的人脸检测器(探测器)提供,其每个矩形列表在图像中对应一个脸。

现在我们已经有了两个标记矩阵,每行有一组坐标对应一个特定的面部特征(如第30行的坐标对应于鼻头)。我们现在要解决如何旋转,翻译和缩放第一个向量,使它们尽可能适配第二个向量的点。一个想法是可以用相同的变换在第一个图像上覆盖第二个图像。

将这个问题数学化,寻找T, s和R,使得下面这个表达式:

<中心> 如何用Python制作一个换脸程序

结果最小,其中R是个2×2正交矩阵,年代是标量,T是二维向量,π和气是上面标记矩阵的行。

事实证明,这类问题可以用“常普罗克汝斯忒斯规分析法”解决:

 def transformation_from_points(里):
  里=points1.astype (numpy.float64)
  points2=points2.astype (numpy.float64)
  c1=numpy。意思是(里,轴=0)
  c2=numpy。意思是(points2轴=0)
  里-=c?
  points2 -=c
  s1=numpy.std(里)
  s2=numpy.std (points2)
  里/=s1
  points2/=s2
  U, v=numpy.linalg.svd(里。T * points2)
  R=(U * Vt) .T
  返回numpy.vstack ([numpy。hstack (((s2/s1) * R,
  c2。T - (s2/s1) * R * c1.T)),
  numpy.matrix ([0。, 0。1。]])

代码实现了这几步:

    <李>将输入矩阵转换为浮点数。这是后续操作的基础。 <李>每一个点集减去它的矩心。一旦为点集找到了一个最佳的缩放和旋转方法,这两个矩心c1和c2就可以用来找到完整的解决方案。 <李>同样,每一个点集除以它的标准偏差。这会消除组件缩放偏差的问题。 <李>使用奇异值分解计算旋转部分。可以在维基百科上看到关于解决正普罗克汝斯忒斯交问题的细节。 <李>利用仿射变换矩阵返回完整的转化。

其结果可以插入OpenCV的cv2。warpAffine函数,将图像二映射到图像一:

 def warp_im (im, M, dshape):
  output_im=numpy。0 (dshape dtype=im.dtype)
  cv2.warpAffine (im,
  M: 2,
  (dshape [1], dshape [0]),
  dst=output_im,
  borderMode=cv2.BORDER_TRANSPARENT,
  旗帜=cv2.WARP_INVERSE_MAP)
  返回output_im 

对齐结果如下:

<中心> 如何用Python制作一个换脸程序

如果我们试图直接覆盖面部特征,很快会看到这个问题:

<中心> 如何用Python制作一个换脸程序

这个问题是两幅图像之间不同的肤色和光线造成了覆盖区域的边缘不连续。我们试着修正:

 COLOUR_CORRECT_BLUR_FRAC=0.6
  LEFT_EYE_POINTS=列表(范围(42岁,48))
  RIGHT_EYE_POINTS=列表(范围(36、42))
  def correct_colours (im1 im2 landmarks1):
  blur_amount=COLOUR_CORRECT_BLUR_FRAC * numpy.linalg.norm (
  numpy。意思是(landmarks1 LEFT_EYE_POINTS,轴=0)
  numpy。意思是(landmarks1 RIGHT_EYE_POINTS,轴=0))
  blur_amount=int (blur_amount)
  如果blur_amount % 2==0:
  blur_amount +=1
  im1_blur=cv2。高斯模糊(im1, (blur_amount blur_amount), 0)
  im2_blur=cv2。高斯模糊(im2, (blur_amount blur_amount), 0)
  #避免被零除错误。
  im2_blur +=128 * (im2_blur & lt;=1.0)
  返回(im2.astype (numpy.float64) * im1_blur.astype (numpy.float64)/im2_blur.astype (numpy.float64)) 

如何用Python制作一个换脸程序