如何通过仿射变换在opencv中实现这一目标?

Yel*_*low 14 python opencv image

我想知道如何复制这张图片中的内容: 在此输入图像描述

要打破它:

  1. 使用dlib(绿点)获取面部地标
  2. 旋转图像,使眼睛水平
  3. 通过平均最左侧和最右侧的地标(蓝点)找到面部的中点,并将图像置于x轴的中心
  4. 通过将眼睛中心从图像顶部放置45%,并将嘴部中心放置在距图像顶部25%的位置,沿y轴固定位置

现在这就是我所拥有的: 在此输入图像描述

我有点坚持第3步,我认为可以通过仿射变换完成?但我完全被第4步难倒,我不知道如何实现它.

如果您需要我提供代码,请告诉我!

编辑:所以在看了@Gal Dreiman的回答后,我能够完美地将脸部居中,以便在我的图像中心找到蓝点.

在此输入图像描述

虽然当我实现他的答案的第二部分时,我最终得到这样的东西:

在此输入图像描述

我看到这些点已经转变到了正确的位置,但这并不是我所期望的结果,因为它非常显着.有任何想法吗?

编辑2:

切换中心点的x,y坐标后,这就是我得到的:

在此输入图像描述

Gal*_*man 8

正如我在第3部分看到的那样,最简单的方法是:

  1. 在图像中查找面部:

    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5,
        minSize=(30, 30),
        flags = cv2.cv.CV_HAAR_SCALE_IMAGE
    )
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于每个面部计算中点:

    for (x, y, w, h) in faces:
        mid_x = x + int(w/2)
        mid_y = y + int(h/2)
    
    Run Code Online (Sandbox Code Playgroud)
  3. 仿射变换图像使您已计算的蓝点居中:

    height, width = img.shape
    x_dot = ...
    y_dot = ...
    
    dx_dot = int(width/2) - x_dot
    dy_dot = int(height/2) - y_dot
    
    M = np.float32([[1,0,dx_dot],[0,1,dy_dot]])
    dst = cv2.warpAffine(img,M,(cols,rows))
    
    Run Code Online (Sandbox Code Playgroud)

希望它有所帮助.

编辑:

关于第4节:为了拉伸(调整大小)图像,您所要做的就是执行仿射变换.为了找到变换矩阵,我们需要输入图像中的三个点及其在输出图像中的相应位置.

    p_1 = [eyes_x, eye_y]
    p_2 = [int(width/2),int(height/2)] # default: center of the image
    p_3 = [mouth_x, mouth_y]

    target_p_1 = [eyes_x, int(eye_y * 0.45)]
    target_p_2 = [int(width/2),int(height/2)] # don't want to change
    target_p_3 = [mouth_x, int(mouth_y * 0.75)]

    pts1 = np.float32([p_1,p_2,p_3])
    pts2 = np.float32([target_p_1,target_p_2,target_p_3])

    M = cv2.getAffineTransform(pts1,pts2)

    output = cv2.warpAffine(image,M,(height,width))
Run Code Online (Sandbox Code Playgroud)

清除问题:

  1. eye_x/ eye_y是眼睛中心的位置.
  2. 这同样适用于mouth_x/ mouth_y,对嘴中心.
  3. target_p_1/2/3 是目标点.

编辑2: 我发现你遇到了麻烦,我希望这次我的建议对你有用:

还有另一种我能想到的方法.您可以通过指向4个点对图像执行"裁剪",让它们定义为包裹脸部的4个点,并根据新位置更改图像透视:

up_left = [x,y]
up_right = [...]
down_left = [...]
down_right = [...]

pts1 = np.float32([up_left,up_right,down_left,down_right])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])

M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(300,300))
Run Code Online (Sandbox Code Playgroud)

所以你要做的就是定义这4点.我的建议是,计算脸部周围的纹路(你已经做过),之后加上delta_xdelta_y(或减去)坐标.