我将如何通过仿射变换在opencv中实现这一点?

Posted

技术标签:

【中文标题】我将如何通过仿射变换在opencv中实现这一点?【英文标题】:How would I achieve this in opencv with an affine transform? 【发布时间】:2017-08-19 22:00:10 【问题描述】:

我想知道如何复制此图像中正在执行的操作:

分解:

    使用 dlib(绿点)获取面部特征 旋转图像,使眼睛水平 通过平均最左边和最右边的地标(蓝点)找到人脸的中点并将图像在 x 轴上居中 通过将眼睛中心放置在距离图像顶部 45%、嘴巴中心距离图像 25% 的位置来沿 y 轴固定位置

现在这就是我所拥有的:

我有点卡在第 3 步,我认为可以通过仿射变换来完成?但是我完全被第 4 步难住了,我不知道我将如何实现它。

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

编辑:所以在查看@Gal Dreiman 的回答后,我能够完美地将脸部居中,使我的图像中心的蓝点。

虽然当我实施他回答的第二部分时,我最终得到了这样的结果:

我看到这些点已被转换到正确的位置,但这不是我想要的结果,因为它非常明显。有什么想法吗?

编辑 2:

切换中心点的x、y坐标后,我得到了:

【问题讨论】:

【参考方案1】:

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

    在图像中查找人脸:

    faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5,
        minSize=(30, 30),
        flags = cv2.cv.CV_HAAR_SCALE_IMAGE
    )
    

    为每个面计算中点:

    for (x, y, w, h) in faces:
        mid_x = x + int(w/2)
        mid_y = y + int(h/2)
    

    仿射变换图像以使您已经计算的蓝点居中:

    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))
    

希望对您有所帮助。

编辑:

关于第 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))

清除:

    eye_x / eye_y 是眼球中心的位置。 同样适用于mouth_x / mouth_y,嘴巴中心。 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))

所以您所要做的就是定义这 4 点。我的建议是计算脸部周围的轮廓(你已经做过),然后在坐标中添加 delta_xdelta_y(或减去)。

【讨论】:

感谢我的形象居中!您对第 4 步有什么想法吗?我将如何缩放图像以使脸部和嘴巴处于正确的位置? 谢谢您的好心先生! @Gal Dreimand 你介意看看我更新的问题吗,我已经成功地将脸部居中,但调整形状的大小并没有按预期进行。 如果您仍然感兴趣,请添加赏金 :) 抱歉耽搁了。我在您的更新中看到,根据您的源点,目标点是正确的:您只想更改 y 轴:那么为什么您的中心点发生了变化(可能而不是第一个点)?

以上是关于我将如何通过仿射变换在opencv中实现这一点?的主要内容,如果未能解决你的问题,请参考以下文章

我想在表 A 中提取一些在表 B 中没有条目的列。如何在 Hive 中实现这一点?

[OpenCV实战]31 使用OpenCV将一个三角形仿射变换到另一个三角形

对 OpenCV 中 getRotationMatrix2D 函数和仿射变换的一点理解

如何在水晶报告中实现这一目标?

OpenCV从仿射矩阵得到旋转量平移量缩放量

OpenCV从仿射矩阵得到旋转量平移量缩放量