Python实现PhotoShop人脸液化变形效果

在PhotoShop中,我们经常利用液化工具的向前工具来对人脸进行形变处理,例如瘦脸、放大眼睛等常规P图操作。

瘦脸与眼睛放大可以算作图像局部扭曲算法的一个应用,其参考文献可以追溯至1993年的一篇博士论文:Interactive Image Warping。这篇论文详细描述了算法原理,并提供了伪码实现。

图像局部扭曲算法有三个:局部缩放(Local Scaling)算法、局部平移(Local Transition)算法和局部旋转(Local Rotation)算法。其中应用局部缩放算法可实现眼睛放大,局部平移算法则可用于实现瘦脸效果。下面来应用图像局部平移算法让一张图片“笑”起来,其背后原理和瘦脸原理如出一辙。

实现效果

在这里插入图片描述

具体实现步骤

  • 利用dlib库的人脸关键点检测器检测出人脸的68个关键点,其68个特征点在人脸中的位置和在关键点序列中的次序如下

    在这里插入图片描述

  • 划定一个圆形选区,一般是要让哪里的局部图像变形就在哪里划定圆形选取,因为这里要让人脸“笑”起来,所以分别在关键点49、60(左嘴角)和55、56(右嘴角)之间划定圆形选区

  • 对于圆形选区里的每一像素,取出其R,G,B各分量,存入3个变量(r, g, b)中(也即,三个变量分别存储选区内的原图像的R,G,B三个通道的数值)

  • 对于圆形选区里的每一个像素U

  • 根据图像局部平移算法公式的映射关系,算出它变形后的位置坐标X(实际运算过程采取逆运算,即由变形后坐标X推出变形前坐标U)

在这里插入图片描述

  • 用双线性插值方法,根据U的位置,和r, g, b中的数值,计算U所在位置处的R,G,B等分量,将R,G,B等分量合成新的像素,作为X处的像素值(bilinearInsert方法)

代码实现(代码已附上详细注释)

import dlib
import cv2
import numpy as np
import math
import matplotlib.pyplot as plt


class FaceAdjust():
    def __init__(self):

        self.predictor_path = "dat/shape_predictor_68_face_landmarks.dat"
        #获取人脸框检测器
        self.detector = dlib.get_frontal_face_detector()
        #获取人脸关键点检测器
        self.predictor = dlib.shape_predictor(self.predictor_path)


    def landmark_dec_dlib_fun(self,img_src):
        img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
        #用于绘制人脸关键点的img
        img_tag = img_src.copy()

        land_marks = []
        rects = self.detector(img_gray, 0)

        for i in range(len(rects)):
            #把人脸关键点列表转为矩阵保存至列表中
            land_marks_node = np.matrix([[p.x, p.y] for p in self.predictor(img_gray, rects[i]).parts()])        
            land_marks.append(land_marks_node)
            #在图中标记出人脸关键点
            for j in land_marks_node:
                pt_pos = (j[0,0],j[0,1])
                cv2.circle(img_tag, pt_pos, 2, (0, 255, 0), -1)
            
        cv2.imwrite(r'tag.jpg', img_tag)
        return land_marks


    '''
    localTranslationWarp:Interactive Image Warping 局部平移算法(移动圆内的像素)
    具体实现步骤
    2.1 对于圆形选区里的每一像素,取出其R,G,B各分量,存入3个变量(r, g, b)中(也即,三个变量分别存储选区内的原图像的R,G,B三个通道的数值)
    2.2 对于圆形选区里的每一个像素U
    2.3 根据图像局部平移变形,算出它变形后的位置坐标精确值X
    2.4 用插值方法,根据U的位置,和r, g, b中的数值,计算U所在位置处的R,G,B等分量,将R,G,B等分量合成新的像素,作为X处的像素值(bilinearInsert方法)
    '''


    def localTranslationWarp(self,srcImg, startX, startY, endX, endY, radius):
        ddradius = float(radius * radius)
        copyImg = np.zeros(srcImg.shape, np.uint8)
        copyImg = srcImg.copy()

        # 计算公式中的|m-c|^2
        ddmc = (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY)
        H, W, C = srcImg.shape
        for i in range(W):
            for j in range(H):
                # 计算该点是否在形变圆的范围之内
                # 优化,第一步,直接判断是会在(startX,startY)的矩阵框中
                if math.fabs(i - startX) > radius and math.fabs(j - startY) > radius:
                    continue

                distance = (i - startX) * (i - startX) + (j - startY) * (j - startY)

                if (distance < ddradius):
                    # 计算出(i,j)坐标的原坐标
                    # 计算公式中右边平方号里的部分
                    ratio = (ddradius - distance) / (ddradius - distance + ddmc)
                    ratio = ratio * ratio

                    # 映射原位置(向后变形,j后+变-即为向前变形)
                    UX = i + ratio * (endX - startX)
                    UY = j + ratio * (endY - startY)

                    # 根据双线性插值法得到UX,UY的值
                    value = self.bilinearInsert(srcImg, UX, UY)
                    # 改变当前 i ,j的值
                    copyImg[j, i] = value

        return copyImg

    """
    bilinearInsert:双线性插值法(变换像素)
    """
    def bilinearInsert(self,src, ux, uy):
        w, h, c = src.shape
        if c == 3:
            x1 = int(ux)
            x2 = x1 + 1
            y1 = int(uy)
            y2 = y1 + 1

            part1 = src[y1, x1].astype(np.float) * (float(x2) - ux) * (float(y2) - uy)
            part2 = src[y1, x2].astype(np.float) * (ux - float(x1)) * (float(y2) - uy)
            part3 = src[y2, x1].astype(np.float) * (float(x2) - ux) * (uy - float(y1))
            part4 = src[y2, x2].astype(np.float) * (ux - float(x1)) * (uy - float(y1))

            insertValue = part1 + part2 + part3 + part4

            return insertValue.astype(np.int8)


    def face_adjust_auto(self,src):
        #1.获取人脸关键点
        landmarks = self.landmark_dec_dlib_fun(src)

        # 如果未检测到人脸关键点,就不进行脸部微调
        if len(landmarks) == 0:
            return


        #2.对嘴巴关键点(左嘴角和右嘴角)进行局部平移算法(微笑)
        thin_image = src
        landmarks_node = landmarks[0]
        start_landmark1 = landmarks_node[48]
        end_landmark1 = landmarks_node[59]
        start_landmark2 = landmarks_node[54]
        end_landmark2 = landmarks_node[55]

        r = math.sqrt((start_landmark1[0, 0] - end_landmark1[0, 0]) * (start_landmark1[0, 0] - end_landmark1[0, 0]) +
            (start_landmark1[0, 1] - end_landmark1[0, 1]) * (start_landmark1[0, 1] - end_landmark1[0, 1]))
        thin_image = self.localTranslationWarp(thin_image, start_landmark1[0, 0], start_landmark1[0, 1], end_landmark1[0,0], end_landmark1[0, 1], r)
        thin_image = self.localTranslationWarp(thin_image, start_landmark2[0, 0], start_landmark2[0, 1], end_landmark2[0,0], end_landmark2[0, 1], r)

        # 显示
        # cv2.imshow('thin', thin_image)
        cv2.imwrite(r'thin.jpg', thin_image)


if __name__ == '__main__':
    src = cv2.imread(r'face_adjust.jpg')
    face_adjust_control = FaceAdjust()
    face_adjust_control.face_adjust_auto(src)

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: opencv是一个开源的计算机视觉库,可以在Python中使用。通过使用opencv的色相饱和度转换功能,可以实现类似Photoshop中对图像进行色相和饱和度的调整。 首先,我们需要导入opencv库,并读取一张图片作为输入图像。可以使用cv2.imread()函数来读取图像。 接下来,我们可以通过调用cv2.cvtColor()函数来将图像转换为HSV色彩空间。HSV颜色模型由色调(Hue),饱和度(Saturation)和亮度(Value)组成。我们只需要调整色调和饱和度,所以我们将图像转换为HSV色彩空间。 然后,我们可以通过使用cv2.convertScaleAbs()函数来调整色相和饱和度的值。该函数有三个参数,分别是输入图像、输出图像和缩放因子。我们可以将缩放因子设置为一个小数,以调整图像的色相和饱和度。 最后,我们可以使用cv2.cvtColor()函数将图像转换回BGR颜色空间,然后可以使用cv2.imshow()函数显示调整后的图像。 下面是一个简单的示例代码: ```python import cv2 # 读取输入图像 image = cv2.imread('image.jpg') # 将图片转换为HSV颜色空间 hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 调整色相和饱和度的值 hue_scale = 0.5 # 色相缩放因子 saturation_scale = 1.5 # 饱和度缩放因子 # 调整色相和饱和度的值 hsv_image[:,:,0] = cv2.convertScaleAbs(hsv_image[:,:,0], alpha=hue_scale) hsv_image[:,:,1] = cv2.convertScaleAbs(hsv_image[:,:,1], alpha=saturation_scale) # 将图片转换回BGR颜色空间 new_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) # 显示调整后的图像 cv2.imshow('Adjusted Image', new_image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这个示例代码中,我们将色相缩放因子设为0.5,饱和度缩放因子设为1.5。你可以根据自己的需要调整这两个值来得到不同的效果。调整后的图像会在一个新的窗口中显示出来。 这样,我们就可以通过opencv和Python实现简单的色相和饱和度调整,类似于Photoshop中的功能。 ### 回答2: 要使用OpenCV和Python实现Photoshop中的色相饱和度功能,可以按照以下步骤进行: 1. 导入必要的库:使用`import cv2`导入OpenCV库。 2. 加载图像:使用`cv2.imread()`函数加载要处理的图像。 3. 转换颜色空间:将加载的图像转换为HSV颜色空间,以便可以对色相和饱和度进行调整。使用`cv2.cvtColor()`函数将图像从BGR颜色空间转换为HSV颜色空间。 4. 调整色相和饱和度:使用`cv2.cvtColor()`函数的第三个参数来调整色相和饱和度。该参数的取值范围为[-180, 180],其中负值表示减少色相或饱和度,正值表示增加色相或饱和度。 5. 转换颜色空间:将调整后的图像转换回BGR颜色空间,以便显示或保存。使用`cv2.cvtColor()`函数将图像从HSV颜色空间转换为BGR颜色空间。 6. 显示或保存结果:使用`cv2.imshow()`函数显示调整后的图像,并使用`cv2.waitKey()`函数等待用户按下键盘上的任意键。或使用`cv2.imwrite()`函数将调整后的图像保存到文件中。 7. 释放资源:使用`cv2.destroyAllWindows()`函数释放窗口和图像资源。 以下是一个示例代码来实现上述步骤: ```python import cv2 # 加载图像 image = cv2.imread('input.jpg') # 转换颜色空间为HSV hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 调整色相和饱和度 hsv_image[..., 0] += 30 # 增加色相 hsv_image[..., 1] *= 1.5 # 增加饱和度 # 转换颜色空间为BGR adjusted_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) # 显示调整后的图像 cv2.imshow('Adjusted Image', adjusted_image) cv2.waitKey(0) # 保存调整后的图像 cv2.imwrite('output.jpg', adjusted_image) # 释放资源 cv2.destroyAllWindows() ``` 这段示例代码实现了将输入图像的色相增加30度,饱和度增加1.5倍的效果。您可以根据实际需求调整这两个参数来实现不同的色相饱和度调整效果。 ### 回答3: 要使用OpenCV在Python实现Photoshop的色相饱和度功能,你需要按照以下步骤进行操作: 1. 导入所需的库和模块: ```python import cv2 import numpy as np ``` 2. 读取图像: ```python image = cv2.imread("your_image.jpg") ``` 3. 将图像转换为HSV颜色空间: ```python hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) ``` 4. 调整色相和饱和度参数: ```python hue_shift = 30 # 色相偏移量(取值范围:-180到180) saturation_factor = 1.5 # 饱和度增强因子(取值范围:0到正无穷) hsv_image[:, :, 0] = (hsv_image[:, :, 0] + hue_shift) % 180 hsv_image[:, :, 1] = hsv_image[:, :, 1] * saturation_factor ``` 5. 将修改后的图像转换回BGR颜色空间: ```python result_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) ``` 6. 显示和保存结果图像: ```python cv2.imshow("Result Image", result_image) cv2.imwrite("result_image.jpg", result_image) cv2.waitKey(0) ``` 通过以上步骤,你可以使用OpenCV和Python实现类似Photoshop的色相饱和度功能。根据需要,你可以调整色相和饱和度的参数来得到不同的效果。记得根据自己的实际情况修改读取和保存图像的路径。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值