Mediapipe 人像分割;实时更换背景;人脸添加特效

news2024/11/19 7:44:46

参考:
https://zhuanlan.zhihu.com/p/476351994

1、Mediapipe 人像分割

import cv2
import mediapipe as mp
import numpy as np
mp_drawing = mp.solutions.drawing_utils
mp_selfie_segmentation = mp.solutions.selfie_segmentation
# 图片人物抠图:
IMAGE_FILES = []
BG_COLOR = (0, 255, 0) # 背景颜色也可以使用其他的照片,要求与原照片尺寸一致
#bg_image = cv2.imread('6.jpg')
MASK_COLOR = (255, 255, 255) # mask图片颜色
file = '1.jpg'
with mp_selfie_segmentation.SelfieSegmentation(model_selection=0) as selfie_segmentation:
    image = cv2.imread(file)
    image_height, image_width, _ = image.shape
    # 在处理之前需要转换图片到RGB颜色空间
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = selfie_segmentation.process(image)
    # 在背景图像上绘制分割图
    #为了改善边界周围的分割,可以考虑在 results.segmentation_mask进行双边过滤
    condition = np.stack((results.segmentation_mask,) * 3, axis=-1) > 0.1
    #生成纯色图像,白色的mask图纸
    #fg_image = np.zeros(image.shape, dtype=np.uint8)
    #fg_image[:] = MASK_COLOR
    fg_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    bg_image = np.zeros(image.shape, dtype=np.uint8)
    bg_image[:] = BG_COLOR
    output_image = np.where(condition, fg_image, bg_image)
    cv2.imshow('output_image',output_image)
    cv2.waitKey(0)
    #cv2.imwrite('selfie0.png', output_image)

2、实时更换背景

准备了三张背景图,按键盘键1,2,3分别更换对应背景图

import cv2
import mediapipe as mp
import numpy as np
mp_drawing = mp.solutions.drawing_utils
mp_selfie_segmentation = mp.solutions.selfie_segmentation


selfie_segmentation =  mp_selfie_segmentation.SelfieSegmentation(model_selection=0)


# 加载视频
cap = cv2.VideoCapture(0)


# 预加载所有背景图像
backgrounds = {
    '1': cv2.resize(cv2.imread('1.jpg'), (640, 480)),
    '2': cv2.resize(cv2.imread('2.jpg'), (640, 480)),
    '3': cv2.resize(cv2.imread('3.jpg'), (640, 480))
}

# 初始化使用的背景
use_bg_1 = False
use_bg_2 = False
use_bg_3 = False

while True:
    ret, image = cap.read()
    # image = cv2.imread(frame)
    image_height, image_width, _ = image.shape
    # 在处理之前需要转换图片到RGB颜色空间
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = selfie_segmentation.process(image)
    # 在背景图像上绘制分割图
    #为了改善边界周围的分割,可以考虑在 results.segmentation_mask进行双边过滤
    condition = np.stack((results.segmentation_mask,) * 3, axis=-1) > 0.7  ##值高点好像分割效果会好点,但不要超过1
    #生成纯色图像,白色的mask图纸
    #fg_image = np.zeros(image.shape, dtype=np.uint8)
    #fg_image[:] = MASK_COLOR
    fg_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    output_image = fg_image
    # bg_image = np.zeros(image.shape, dtype=np.uint8)
    # bg_image[:] = BG_COLOR
    # output_image = np.where(condition, fg_image, bg_image)
    # cv2.imshow('output_image',fg_image)
    #cv2.imwrite('selfie0.png', output_image)
    if cv2.waitKey(1) == ord('q'):
        break
    key = cv2.waitKey(1)
    if key == ord('1'):
        use_bg_1 = True
        use_bg_2 = False
        use_bg_3 = False
    elif key == ord('2'):
        use_bg_2 = True
        use_bg_1 = False
        use_bg_3 = False
    elif key == ord('3'):  
        use_bg_3 = True
        use_bg_1 = False
        use_bg_2 = False
    
    if use_bg_1:
        output_image = np.where(condition, fg_image,backgrounds['1']).astype(np.uint8)
    if use_bg_2:
        output_image = np.where(condition, fg_image, backgrounds['2']).astype(np.uint8)
    if use_bg_3:
        output_image = np.where(condition, fg_image, backgrounds['3']).astype(np.uint8)
    



    cv2.imshow('output_image',output_image)

cap.release()
cv2.destroyAllWindows()

3、人脸添加特效

参考:https://blog.csdn.net/weixin_40062244/article/details/128409286

cv2保存和读取中文路径异常解决:


读取:
img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), 1)
file_path为图片路径


保存:
cv2.imencode('.jpg', src)[1].tofile(save_path)
第一个’.jpg’为保存文件格式,save_path为保存图片路径
cv2.imencode('.jpg', img)[1].tofile(‘C:\1.jpg’)

代码,添加胡子特效,根据检测关键点计算对应区域

在这里插入图片描述

# 导入所需库
import cv2
import mediapipe as mp
import math
import matplotlib.pyplot as plt
import time
import numpy as np


##解决cv2读取中文路径问题
def cv_img(file_path):
    cv_img = cv2.imdecode(np.fromfile(file_path,dtype=np.uint8),-1)
    return cv_img

# 获取人脸关键点
def get_landmarks(image, face_mesh):
    """
    :param image: ndarray图像
    :param face_mesh: 人脸检测模型
    :return:人脸关键点列表,如[{0:(x,y),1:{x,y},...},{0:(x,y),1:(x,y)}]
    """
    landmarks = []
    height, width = image.shape[0:2]
    # 人脸关键点检测
    results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    # 解释检测结果
    if results.multi_face_landmarks:
        for face_landmarks in results.multi_face_landmarks:
            i = 0
            points = {}
            # 根据图像的高度和宽度还原关键点位置
            for landmark in face_landmarks.landmark:
                x = math.floor(landmark.x * width)
                y = math.floor(landmark.y * height)
                points[i] = (x, y)
                i += 1
            landmarks.append(points)

    return landmarks



def process_effects(landmarks,icon_path, icon_name):
    """
    :param landmarks: 检测到的人脸关键点列表
    :param icon_path: 特效图像地址
    :param icon_name: 特效名称
    :return:处理好的特效图像、特效宽、特效高
    """
    # 特效关键点,用于调整特效的尺寸
    effect_landmarks = {"beard": ((landmarks[132][0], landmarks[5][1]), (landmarks[361][0], landmarks[0][1])),
                        "eyeglass": ((landmarks[127][0], landmarks[151][1]), (landmarks[356][0], landmarks[195][1])),
                        "halfmask": ((landmarks[162][0]-50, landmarks[10][1]-50), (landmarks[389][0]+50, landmarks[195][1]+50))}

    # 读取特效图像
    icon = cv2.imread(icon_path)
    print("icon:",icon.shape)
    # 选择特效关键点
    pt1, pt2 = effect_landmarks[icon_name]
    x, y, x_w, y_h = pt1[0], pt1[1], pt2[0], pt2[1]
    # 调整特效的尺寸
    w, h = x_w - x, y_h - y
    effect = cv2.resize(icon, (w, h))

    return effect, w, h


def swap_non_effcet2(effect, roi, threshold=240):
    """
    :param effect: 特效图像
    :param roi: ROI区域
    :param threshold: 阈值
    :return: 消除背景后的特效图像
    """

    # (1)特效图像灰度化
    effect2gray = cv2.cvtColor(effect, cv2.COLOR_BGR2GRAY)
    # (2)特效图像二值化
    ret, effect2wb = cv2.threshold(effect2gray, threshold, 255, cv2.THRESH_BINARY)
    # (3)消除特效的白色背景
    effectwb = cv2.bitwise_and(roi, roi, mask=effect2wb)

    # (4)反转二值化后的特效
    effect2wb_ne = cv2.bitwise_not(effect2wb)
    # (5)处理彩色特效
    effectcolor = cv2.bitwise_and(effect, effect, mask=effect2wb_ne)
    # (6) 组合彩色特效与黑色特效
    effect_final = cv2.add(effectcolor, effectwb)

    return effect_final




# 模型配置
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=False,  # 静态图片设置为False,视频设置为True
                                  max_num_faces=3,  # 能检测的最大人脸数
                                  refine_landmarks=True,  # 是否需要对嘴唇、眼睛、瞳孔的关键点进行定位,
                                  min_detection_confidence=0.5,  # 人脸检测的置信度
                                  min_tracking_confidence=0.5)  # 人脸追踪的置信度(检测图像时可以忽略)

# 读取图像

# 定义中文路径字符串
path_str = r"D:\opencv2\刘亦菲.jpg"
image = cv2.imdecode(np.fromfile(path_str, dtype=np.uint8), 1)  #中文路径读取异常解决方式
print(image.shape)
# 获取关键点
face_landmarks = get_landmarks(image, face_mesh)

# ROI区域中心关键点
center = {"beard": 164, "eyeglass": 168, "halfmask": 9}


image_copy = image.copy()
icon_name = "beard"
p = 164
# 处理特效

for landmarks in face_landmarks:
    effect, w, h = process_effects(landmarks, icon_name+".jpg", icon_name)
    # 确定ROI
    p = center[icon_name]
    roi = image[landmarks[p][1] - int(h / 2):landmarks[p][1] - int(h / 2) + h,
          landmarks[p][0] - int(w / 2):landmarks[p][0] - int(w / 2) + w]

    if effect.shape[:2] == roi.shape[:2]:
        # 消除特效图像中的白色背景区域
        s = time.time()
        # 第一种方法
        # swap_non_effcet1(effect,roi,240)
        # 第二种方法
        effect = swap_non_effcet2(effect, roi,240)

        print(time.time()-s) # 计算处理时间

        # 将处理好的特效添加到人脸图像上
        image[landmarks[p][1] - int(h / 2):landmarks[p][1] - int(h / 2) + h,
        landmarks[p][0] - int(w / 2):landmarks[p][0] - int(w / 2) + w] = effect


cv2.imwrite("bread_liu.jpg", image, params=None)
# # 利用matplotlib展示
# plt.figure(figsize=(30, 10))
# plt.imshow(image[:, :, ::-1])

在这里插入图片描述

摄像头实时添加特效胡子:

# 导入所需库
import cv2
import mediapipe as mp
import math
import matplotlib.pyplot as plt
import time
import numpy as np


##解决cv2读取中文路径问题
def cv_img(file_path):
    cv_img = cv2.imdecode(np.fromfile(file_path,dtype=np.uint8),-1)
    return cv_img

# 获取人脸关键点
def get_landmarks(image, face_mesh):
    """
    :param image: ndarray图像
    :param face_mesh: 人脸检测模型
    :return:人脸关键点列表,如[{0:(x,y),1:{x,y},...},{0:(x,y),1:(x,y)}]
    """
    landmarks = []
    height, width = image.shape[0:2]
    # 人脸关键点检测
    results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    # 解释检测结果
    if results.multi_face_landmarks:
        for face_landmarks in results.multi_face_landmarks:
            i = 0
            points = {}
            # 根据图像的高度和宽度还原关键点位置
            for landmark in face_landmarks.landmark:
                x = math.floor(landmark.x * width)
                y = math.floor(landmark.y * height)
                points[i] = (x, y)
                i += 1
            landmarks.append(points)

    return landmarks



def process_effects(landmarks,icon_path, icon_name):
    """
    :param landmarks: 检测到的人脸关键点列表
    :param icon_path: 特效图像地址
    :param icon_name: 特效名称
    :return:处理好的特效图像、特效宽、特效高
    """
    # 特效关键点,用于调整特效的尺寸
    effect_landmarks = {"beard": ((landmarks[132][0], landmarks[5][1]), (landmarks[361][0], landmarks[0][1])),
                        "eyeglass": ((landmarks[127][0], landmarks[151][1]), (landmarks[356][0], landmarks[195][1])),
                        "halfmask": ((landmarks[162][0]-50, landmarks[10][1]-50), (landmarks[389][0]+50, landmarks[195][1]+50))}

    # 读取特效图像
    icon = cv2.imread(icon_path)
    print("icon:",icon.shape)
    # 选择特效关键点
    pt1, pt2 = effect_landmarks[icon_name]
    x, y, x_w, y_h = pt1[0], pt1[1], pt2[0], pt2[1]
    # 调整特效的尺寸
    w, h = x_w - x, y_h - y
    effect = cv2.resize(icon, (w, h))

    return effect, w, h


def swap_non_effcet2(effect, roi, threshold=240):
    """
    :param effect: 特效图像
    :param roi: ROI区域
    :param threshold: 阈值
    :return: 消除背景后的特效图像
    """

    # (1)特效图像灰度化
    effect2gray = cv2.cvtColor(effect, cv2.COLOR_BGR2GRAY)
    # (2)特效图像二值化
    ret, effect2wb = cv2.threshold(effect2gray, threshold, 255, cv2.THRESH_BINARY)
    # (3)消除特效的白色背景
    effectwb = cv2.bitwise_and(roi, roi, mask=effect2wb)

    # (4)反转二值化后的特效
    effect2wb_ne = cv2.bitwise_not(effect2wb)
    # (5)处理彩色特效
    effectcolor = cv2.bitwise_and(effect, effect, mask=effect2wb_ne)
    # (6) 组合彩色特效与黑色特效
    effect_final = cv2.add(effectcolor, effectwb)

    return effect_final




# 模型配置
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=False,  # 静态图片设置为False,视频设置为True
                                  max_num_faces=3,  # 能检测的最大人脸数
                                  refine_landmarks=True,  # 是否需要对嘴唇、眼睛、瞳孔的关键点进行定位,
                                  min_detection_confidence=0.5,  # 人脸检测的置信度
                                  min_tracking_confidence=0.5)  # 人脸追踪的置信度(检测图像时可以忽略)




# 加载视频
cap = cv2.VideoCapture(0)
while True:
    ret, image = cap.read()
    # 定义中文路径字符串
    # path_str = r"D:\opencv2\刘亦菲.jpg"
    # image = cv2.imdecode(np.fromfile(path_str, dtype=np.uint8), 1)  #中文路径读取异常解决方式
    # print(image.shape)
    # 获取关键点
    face_landmarks = get_landmarks(image, face_mesh)

    # ROI区域中心关键点
    center = {"beard": 164, "eyeglass": 168, "halfmask": 9}


    image_copy = image.copy()
    icon_name = "beard"
    p = 164
    # 处理特效

    for landmarks in face_landmarks:
        effect, w, h = process_effects(landmarks, icon_name+".jpg", icon_name)
        # 确定ROI
        p = center[icon_name]
        roi = image[landmarks[p][1] - int(h / 2):landmarks[p][1] - int(h / 2) + h,
            landmarks[p][0] - int(w / 2):landmarks[p][0] - int(w / 2) + w]

        if effect.shape[:2] == roi.shape[:2]:
            # 消除特效图像中的白色背景区域
            s = time.time()
            # 第一种方法
            # swap_non_effcet1(effect,roi,240)
            # 第二种方法
            effect = swap_non_effcet2(effect, roi,240)

            print(time.time()-s) # 计算处理时间

            # 将处理好的特效添加到人脸图像上
            image[landmarks[p][1] - int(h / 2):landmarks[p][1] - int(h / 2) + h,
            landmarks[p][0] - int(w / 2):landmarks[p][0] - int(w / 2) + w] = effect

    cv2.imshow('output_image',image)
    if cv2.waitKey(20) & 0xff == ord('q'):
        break
 
       
 
cap.release()
cv2.destroyWindow("camera")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/694495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea生成serialVersionUID序列号

设置idea file->settings,搜索serialVersionUID,勾选框起来的两项 实体类实现Serializable接口 Data public class User implements Serializable { }鼠标放到类名上 点击提示的uid 生成的uid 结束! hy:17 生活是一面镜子,给予我们…

springboot 停车场管理系统-计算机毕设 附源码82061

springboot 停车场管理系统 2023年5月 摘要 由于数据库和数据仓库技术的快速发展,停车场管理系统建设越来越向模块化、智能化、自我服务和管理科学化的方向发展。停车场管理系统对处理对象和服务对象,自身的系统结构,处理能力,都…

GO 基本配置

其他 IDEA 配置go语言环境 https://blog.csdn.net/weixin_45719444/article/details/121726325 关于IDEA的 plugins下找不到GO插件 点击安装 安装插件 Go 安装插件 Generate struct tags for golang

Flink CDC 2.4 正式发布,新增 Vitess 数据源,更多连接器支持增量快照,升级 Debezium 版本...

01 Flink CDC 简介 Flink CDC [1] 是基于数据库的日志 CDC 技术,实现了全增量一体化读取的数据集成框架。配合 Flink 优秀的管道能力和丰富的上下游生态,Flink CDC 可以高效实现海量数据的实时集成。 作为新一代的实时数据集成框架,Flink CDC…

二进制搭建Kubernetes集群(三)——部署多master

本文将完成多master集群的部署,即部署master02,以及nginx负载均衡、keepalived高可用 多master集群架构图: 架构说明: node节点的kubelet只能对接一个master节点的apiserver,不可能同时对接多个master节点的apiserver…

【Solr】中文分词配置

提示:在设置中文分词前需确保已经生成过core,未生成core的可以使用:solr create -c "自定义名称"进行定义。 未分词前的效果预览: 下载分词器: 下载地址: https://mvnrepository.com/artifact/com.github.m…

山西电力市场日前价格预测【2023-06-29】

日前价格预测 预测明日(2023-06-29)山西电力市场全天平均日前电价为407.26元/MWh。其中,最高日前价格为539.37元/MWh,预计出现在21: 15。最低日前电价为312.43元/MWh,预计出现在13: 00。以上预测仅供学习参考&#xff…

Java调用ssl异常,javax.net.ssl.SSLHandshakeException: No appropriate protocol

现象:sqlserver 2017 安装在docker里,系统是mac 13,java 1.8.371运行java程序提示上面ssl错误,根据百度提供的方法,修改文件,重启程序搞定。 解决办法:java.security 找到这个文件修改保存 发…

RPC(Remote Procedure Call)学习

目录 一、概念 二、RPC 调用基本流程 一、概念 RPC 全称是 Remote Procedure Call (远程过程调用),它是一种通过网络从远程计算机程序上请求服务,可以提供终结点映射程序以及RPC服务,而不需要了解底层网络技术的协议…

三位数字显示电容测试表

广大电子爱好者都有这样的体会,中、高档数字万用表虽有电容测试挡位,但测量范围一般仅为 1pF~20F,往往不能满足使用者的需要,给电容测量带来不便。本电路介绍的三位数显示电容测试表采用四块集成电路,电路简洁、容易制…

element-ui中el-table设置固定高度后,底部合计栏被遮盖

如图: 解决办法:el-table加上ref"summaryTab",然后在自定义合计计算方法getSummaries中加上如下代码就ok了 this.$nextTick(() > {this.$refs.summaryTab.doLayout(); }); 没用使用自定义合计计算函数的,也可以写在updated中,如下: updated() {this.$nextTick((…

关于ipad:无法验证服务器身份

ipad 连接网络后,有时候会冒出这个弹窗,并且关掉后仍继续弹出 可以尝试以下几种方法:(我是用③解决的) ①. 确保你的iPad连接的是稳定的网络。有时候网络连接不稳定会导致无法验证服务器身份。 我们学校这个校园网…

Karl Guttag评Vision Pro(三):为什么飞机上VR观影体验不佳?

在过去25年里,AR/VR头显显示技术得到长足发展,采用的屏幕规格越来越高。据早前报告预测,VR头显安装基数会在2023年达到约2500万台。尽管如此,相比于无处不在的手机,我们几乎看不到周围有人随身携带AR/VR头显&#xff0…

APP为什么没有被小程序取代呢?

在科技行业日新月异的发展下,一直存在一种声音,认为小程序将逐步取代APP。然而,事实却并非如此。APP至今仍然以其独特的优势,坚挺地存在于市场之中。这是为何呢?以下是我们对此的几点考察。 首先,APP在功能…

「RPA中国杯 · 第五届RPA极客挑战赛」成功举办及获奖名单公示

2023年6月26日,「RPA中国杯 第五届RPA极客挑战赛」在苏州国际博览中心圆满结束。本次挑战赛由RPA中国和全球人工智能产品应用博览会主办,容智信息、金智维、弘玑Cyclone、UiPath联合主办,centific、中投创展协办。 RPA已经成为提高企业生产…

uniapp 详细封装缓存定时过期方法,详细使用过程

最近在开发一个uniapp的项目,中间我们需要给缓存定时,为了解决这个问题,封装了一个方法用来解决这个问题,当时遇到这个问题是因为在项目中要给阿里的OSS上传文件,上传之间先要向服务端请求获取授权,授权我们…

3、动手学深度学习——多层感知机:多层感知机的实现(从零实现+内置函数实现)

1、多层感知机基础知识 1. 简述 加入隐藏层和激活函数,可以将线性模型变成非线性模型,引入了非线性拟合能力。 我们通过在网络中加入一个或多个隐藏层来克服线性模型的限制,使其能处理更普遍的函数关系类型。要做到这一点,最简…

密码学—DES加密算法

文章目录 DES流程DES细节生成密钥DES加密E盒扩展S盒替换P盒置换 DES流程 因为DES是对比特流进行加密的,所以信息在加密之前先转为二进制比特流 1:生成16把密钥 只取给出的密钥比特流中64位,不够64则补0对64位进行PC1表置换,64位进…

vscode搭建汇编环境

汇编语言环境的配置 教程 视频教程 https://www.nasm.us/pub/nasm/releasebuilds/?CM;OD 下载zip压缩包,去目录去解压,然后把根目录配置到环境的变量 vscode搭建汇编环境 插件 assembly Hex editor 这个是用来显示.exe文件的十六字进制的显示 下载…

基于 DTS 同步 MySQL 全增量数据至 CKafka,构建实时数仓的最佳实践

背景介绍 随着 IT 技术与大数据的不断发展,越来越多的企业开始意识到数据的价值,通过大数据分析,可以帮助企业更深入地了解用户需求、更好地洞察市场趋势。目前大数据分析在每个业务运营中都发挥着重要作用,成为企业提升市场竞争…