[Opencv基础]人脸磨皮

我们可以看一下下面一张图片
[Opencv基础]人脸磨皮_第1张图片
可以看到有很多斑点,女生都想让图片的皮肤好看一点,那我们可以做什么操作呢?
1.PS磨皮
2.图像处理磨皮

我们可以想象一下,我们对图像磨皮是怎么做的?最简单的我们对整张图片进行一个卷积操作

import cv2
import matplotlib.pyplot as plt

//函数是,opencv使用的是BGR格式,屏幕显示的是RGB,显示到屏幕需要进行转换
def t2s(img):
    return cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

img = cv2.imread("girlpng")

import numpy as np
//制作一个归一化的3*3卷积核
kernel = np.ones((3,3),np.float32)
kernel = kernel/9.
print(kernel)
print(img.shape)
//使用cv2对图片进行卷积
result = cv2.filter2D(img,-1,kernel)
plt.figure(figsize=(20,20))
//显示处理后的图片并排和原图片显示
plt.imshow(t2s(cv2.hconcat([img,result])))
plt.show()


可以看到斑点不是很淡了一点,我们可以进一步采用更大的卷积核来做处理。

kernel_size=17
kernel = np.ones((kernel_size,kernel_size),np.float32)/(kernel_size*kernel_size)
img1 = cv2.filter2D(img,-1,kernel)
result = cv2.filter2D(img1,-1,kernel)
plt.figure(figsize=(20,20))
plt.imshow(t2s(cv2.hconcat([img,result])))
plt.show()

[Opencv基础]人脸磨皮_第2张图片
这样做磨皮更加明显了,但是也同时会对整张图片有一定精度会有损失。
那有没办法只对皮肤进行磨皮呢?
我们需要先对皮肤区分出来,而我们人眼对HSV格式的参数更加敏感,通过HSV参数可以判断出人皮肤的色值区域,从而隔离出人脸皮肤的位置。

result_show=result.copy()
# 肤色检测
# 来源 https://www.cnblogs.com/demodashi/p/9437559.html
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 把图像转换到HSV色域
(_h, _s, _v) = cv2.split(hsv) # 图像分割, 分别获取h, s, v 通道分量图像
skin3 = np.zeros(_h.shape, dtype=np.float32)  # 根据源图像的大小创建一个全0的矩阵,用于保存图像数据

(height,width) = _h.shape # 获取源图像数据的长和宽

# 遍历图像, 判断HSV通道的数值, 如果在指定范围中, 则置把新图像的点设为255,否则设为0
for i in  range(0, height):
    for j in  range(0, width):
        //这是黄种人皮肤色域
        if (_h[i][j] >  5) and (_h[i][j] <  120) and (_s[i][j] >  18) and (_s[i][j] <  255) and (_v[i][j] >  50) and (_v[i][j] <  255):
            skin3[i][j] =  1.0
        else:
            skin3[i][j] =  0.0
            result_show[i][j]=img[i][j]
plt.figure(figsize=(20,20))
plt.imshow(t2s(cv2.hconcat([img,result_show,result])))
plt.show()

[Opencv基础]人脸磨皮_第3张图片
中间的是皮肤磨皮以及皮肤外区域不处理叠加的图
skin矩阵记录的是人脸色值检测的图,我们可以看到白色的区域为人脸区域

plt.figure(figsize=(10,10))
plt.imshow(t2s(skin3))
plt.show()

[Opencv基础]人脸磨皮_第4张图片
关于皮肤识别可以看皮肤区域检测
里面有基于HSV和RGB色值检测,以及opencv提供的适应器

以上使用灰度图来查看人面皮肤区域(白人和黑人的皮肤范围呢?)
这里可以采用中值滤波等各种滤波方式来处理图像
python各种常见滤波实现
参考了其他方案,有人使用了双边滤波的方案进行滤波

result_bila = cv2.bilateralFilter(img,25,83,83)
plt.figure(figsize=(20,20))
plt.imshow(t2s(cv2.hconcat([img,result_show,result_bila,result])))
plt.show()

[Opencv基础]人脸磨皮_第5张图片
使用双边滤波并替换人脸区域的方案,可以看出一些细致的细节还是被卷积掉了。

result_fb = result_bila.copy()
# 遍历图像, 判断HSV通道的数值, 如果在指定范围中, 则置把新图像的点设为255,否则设为0
for i in  range(0, height):
    for j in  range(0, width):
        if (_h[i][j] >  5) and (_h[i][j] <  120) and (_s[i][j] >  18) and (_s[i][j] <  255) and (_v[i][j] >  50) and (_v[i][j] <  255):
            1.0
        else:
            result_fb[i][j]=img[i][j]
plt.figure(figsize=(20,20))
plt.imshow(t2s(cv2.hconcat([img,result_show,result_fb,result_bila,result])))
plt.show()

[Opencv基础]人脸磨皮_第6张图片
第三张是使用人脸区域替换加双边滤波的图像,对比第四张,很明显眼神会更加发亮。
下面有一种经验使用的opencv使用的磨平算法,可以参照磨皮检测和算法

import numpy as np
#Dest =(Src * (100 - Opacity) + (Src + 2 * GuassBlur(EPFFilter(Src) - Src + 128) - 256) * Opacity) /100 ;
def filter_gaussian(img, v1, v2):
    dst = np.zeros_like(img)
    dx = v1*5
    fc = v1*12.5
    p = 0.1

    #双边滤波
    temp1 = cv2.bilateralFilter(img,dx,fc,fc)
    #图像矩阵相减,得到人脸轮廓
    temp2 = cv2.subtract(temp1,img)
    temp2 = cv2.add(temp2,(10,10,10,128))
    #高斯模糊
    temp3 = cv2.GaussianBlur(temp2,(2*v2-1,2*v2-1),0)
    #原图叠加
    temp4 = cv2.add(img,temp3)
    #按权重混合
    dst1 = cv2.addWeighted(img,p,temp4,1-p,0.0)
    dst = cv2.add(dst1,(10,10,10,255))
    plt.figure(figsize=(20,20))
    plt.imshow(t2s(cv2.hconcat([img,dst,result_fb])))
#     plt.imshow(t2s(cv2.hconcat([img,temp1,temp2,temp3,temp4,dst1,dst])))
    plt.show()
    return dst
dst = filter_gaussian(img,7,4)

中间是算法的效果图
[Opencv基础]人脸磨皮_第7张图片

你可能感兴趣的:(opencv,计算机视觉,python)