探索MediaPipe的人像分割

MediaPipe是Google开源的计算机视觉处理框架,基于TensorFlow来训练模型。图像分割模块提供人像分割、头发分割、多类分割。本文主要探索如何实现人像分割,当然在人像分割基础上,我们可以做背景替换、背景模糊。

目录

一、配置参数与模型

1、配置参数

2、分割模型

2.1 人像分割模型

2.2  头发分割模型

2.3 多类分割模型

二、工程配置

三、初始化工作

1、初始化人像分割

2、初始化摄像头

四、人像分割

1、运行人像分割 

2、绘制人像分割

五、分割效果

一、配置参数与模型

1、配置参数

图像分割的参数包括:运行模式、输出类别掩码、输出置信度掩码、标签语言、结果回调,具体如下表所示:

参数描述取值范围默认值
running_mode

IMAGE:单个图像

VIDEO:视频帧

LIVE_STREAM:实时流

{IMAGE,VIDEO,

LIVE_STREAM}

IMAGE
output_category_mask输出的类别掩码Booleanfalse
output_confidence_mask输出的置信度掩码Booleantrue
display_names_locale标签名称的语言Locale codeen
result_callback结果回调(用于LIVE_STREAM模式)N/AN/A

2、分割模型

图像分割的模型有deeplabv3、haird_segmenter、selfie_multiclass、selfie_segmenter。其中,自拍的人像分割使用的模型是selfie_segmenter。相关模型如下图所示:

2.1 人像分割模型

人像分割输出两类结果:0表示背景、1表示人像。提供两种形状的模型,如下图所示:

 

2.2  头发分割模型

头发分割也是输出两类结果:0表示背景、1表示头发。我们在识别到头发时,可以重新给头发上色,或者添加特效。

2.3 多类分割模型

多类分割包括:背景、头发、身体皮肤、面部皮肤、衣服、其他部位。数值对应关系如下:

0 - background
1 - hair
2 - body-skin
3 - face-skin
4 - clothes
5 - others (accessories)

二、工程配置

以Android平台为例,首先导入MediaPipe相关包:

implementation 'com.google.mediapipe:tasks-vision:0.10.0'

然后运行下载模型的task,并且指定模型保存路径:

project.ext.ASSET_DIR = projectDir.toString() + '/src/main/assets'apply from: 'download_models.gradle'

图像分割模型有4种,可以按需下载:

task downloadSelfieSegmenterModelFile(type: Download) {src 'https://storage.googleapis.com/mediapipe-models/image_segmenter/' +'selfie_segmenter/float16/1/selfie_segmenter.tflite'dest project.ext.ASSET_DIR + '/selfie_segmenter.tflite'overwrite false
}preBuild.dependsOn downloadSelfieSegmenterModelFile

三、初始化工作

1、初始化人像分割

人像分割的初始化主要有:设置运行模式、加载对应的分割模型、配置参数,示例代码如下:

   fun setupImageSegmenter() {val baseOptionsBuilder = BaseOptions.builder()// 设置运行模式when (currentDelegate) {DELEGATE_CPU -> {baseOptionsBuilder.setDelegate(Delegate.CPU)}DELEGATE_GPU -> {baseOptionsBuilder.setDelegate(Delegate.GPU)}}// 加载对应的分割模型when(currentModel) {MODEL_DEEPLABV3 -> { //DeepLab V3baseOptionsBuilder.setModelAssetPath(MODEL_DEEPLABV3_PATH)}MODEL_HAIR_SEGMENTER -> { // 头发分割baseOptionsBuilder.setModelAssetPath(MODEL_HAIR_SEGMENTER_PATH)}MODEL_SELFIE_SEGMENTER -> { // 人像分割baseOptionsBuilder.setModelAssetPath(MODEL_SELFIE_SEGMENTER_PATH)}MODEL_SELFIE_MULTICLASS -> { // 多类分割baseOptionsBuilder.setModelAssetPath(MODEL_SELFIE_MULTICLASS_PATH)}}try {val baseOptions = baseOptionsBuilder.build()val optionsBuilder = ImageSegmenter.ImageSegmenterOptions.builder().setRunningMode(runningMode).setBaseOptions(baseOptions).setOutputCategoryMask(true).setOutputConfidenceMasks(false)// 检测结果异步回调if (runningMode == RunningMode.LIVE_STREAM) {optionsBuilder.setResultListener(this::returnSegmentationResult).setErrorListener(this::returnSegmentationHelperError)}val options = optionsBuilder.build()imagesegmenter = ImageSegmenter.createFromOptions(context, options)} catch (e: IllegalStateException) {imageSegmenterListener?.onError("Image segmenter failed to init, error:${e.message}")} catch (e: RuntimeException) {imageSegmenterListener?.onError("Image segmenter failed to init. error:${e.message}", GPU_ERROR)}}

2、初始化摄像头

摄像头的初始化步骤包括:获取CameraProvider、设置预览宽高比、配置图像分析参数、绑定camera生命周期、关联SurfaceProvider。

    private fun setUpCamera() {val cameraProviderFuture =ProcessCameraProvider.getInstance(requireContext())cameraProviderFuture.addListener({// 获取CameraProvidercameraProvider = cameraProviderFuture.get()// 绑定camerabindCamera()}, ContextCompat.getMainExecutor(requireContext()))}private fun bindCamera() {val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera init failed.")val cameraSelector = CameraSelector.Builder().requireLensFacing(cameraFacing).build()// 预览宽高比设置为4:3preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3).setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation).build()// 配置图像分析的参数imageAnalyzer =ImageAnalysis.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3).setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation).setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888).build().also {it.setAnalyzer(backgroundExecutor!!) { image ->imageSegmenterHelper.segmentLiveStreamFrame(image,cameraFacing == CameraSelector.LENS_FACING_FRONT)}}cameraProvider.unbindAll()try {// 绑定camera生命周期camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalyzer)// 关联SurfaceProviderpreview?.setSurfaceProvider(fragmentCameraBinding.viewFinder.surfaceProvider)} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc)}}

四、人像分割

1、运行人像分割 

以摄像头的LIVE_STREAM模式为例,首先拷贝图像数据,然后图像处理:旋转与镜像,接着把Bitmap对象转换为MPImage,最后执行人像分割。示例代码如下:

    fun segmentLiveStreamFrame(imageProxy: ImageProxy, isFrontCamera: Boolean) {val frameTime    = SystemClock.uptimeMillis()val bitmapBuffer = Bitmap.createBitmap(imageProxy.width,imageProxy.height, Bitmap.Config.ARGB_8888)// 拷贝图像数据imageProxy.use {bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer)}val matrix = Matrix().apply {// 旋转图像postRotate(imageProxy.imageInfo.rotationDegrees.toFloat())// 如果是前置camera,需要左右镜像if(isFrontCamera) {postScale(-1f, 1f, imageProxy.width.toFloat(), imageProxy.height.toFloat())}}imageProxy.close()val rotatedBitmap = Bitmap.createBitmap(bitmapBuffer, 0, 0,bitmapBuffer.width, bitmapBuffer.height, matrix, true)// 转换Bitmap为MPImageval mpImage = BitmapImageBuilder(rotatedBitmap).build()// 执行人像分割imagesegmenter?.segmentAsync(mpImage, frameTime)}

2、绘制人像分割

首先把检测到的背景标记颜色,然后计算缩放系数,主动触发draw操作:

    fun setResults(byteBuffer: ByteBuffer,outputWidth: Int,outputHeight: Int) {val pixels = IntArray(byteBuffer.capacity())for (i in pixels.indices) {// Deeplab使用0表示背景,其他标签为1-19. 所以这里使用20种颜色val index = byteBuffer.get(i).toUInt() % 20Uval color = ImageSegmenterHelper.labelColors[index.toInt()].toAlphaColor()pixels[i] = color}val image = Bitmap.createBitmap(pixels, outputWidth, outputHeight, Bitmap.Config.ARGB_8888)// 计算缩放系数val scaleFactor = when (runningMode) {RunningMode.IMAGE,RunningMode.VIDEO -> {min(width * 1f / outputWidth, height * 1f / outputHeight)}RunningMode.LIVE_STREAM -> {max(width * 1f / outputWidth, height * 1f / outputHeight)}}val scaleWidth = (outputWidth * scaleFactor).toInt()val scaleHeight = (outputHeight * scaleFactor).toInt()scaleBitmap = Bitmap.createScaledBitmap(image, scaleWidth, scaleHeight, false)invalidate()}

最终执行绘制的draw函数,调用canvas来绘制bitmap:

    override fun draw(canvas: Canvas) {super.draw(canvas)scaleBitmap?.let {canvas.drawBitmap(it, 0f, 0f, null)}}

五、分割效果

人像分割本质是把人像和背景分离,最终效果图如下: 

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AIGC】BaiChuan7B开源大模型介绍、部署以及创建接口服务

模型介绍 baichuan-7B是由百川智能开发的一个开源的大规模预训练模型。基于Transformer结构,在大约1.2万亿tokens上训练的70亿参数模型,支持中英双语,上下文窗口长度为4096。在标准的中文和英文权威benchmark(C-EVAL/MMLU&#x…

探索思维导图:提升思维能力与效率的利器

思维导图作为一种强大的思考工具,已经被广泛应用于各个领域,从学习、工作到创意思维和项目管理。 本文将为您介绍思维导图的基本概念、使用方法以及它对思维能力和效率提升的价值。通过学习和掌握思维导图,您将能够更系统地组织和表达您的思…

M3 architecure

using one picture from arm document . 1. 3级别流水线哈弗架构 采用三级流水线,为了简单,常见的流水线5级,对于带有OOOB的12级较为常见,足可见M3的架构简化了很多 2. thumb 加ARMV7-M ISA 指令集就是硬件和软件的中间交互规则…

群载波应急广播主机的应用

一、 概述 群载波主机是专为山洪灾害预警、气象预警、地质灾害预警设计的一款智能IP群载波主机。该群载波主机可通过网络实现与控制中心通讯,用户可实时远程控制功放的开关机状态以及检测设备的主要信息。群载波主机主要用于接收网络信号,与控制中心通讯…

剑指 Offer 33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 观察数组我们可以得到一些初始数据。 数组的最后一位元素为根。根的左子树小于根数据,右子树…

Java面试题及答案整理( 金九银十最新版,持续更新)

最近可能有点闲的慌,没事就去找面试面经,整理了一波面试题。我大概是分成了 Java 基础、中级、高级,分布式,Spring 架构,多线程,网络,MySQL,Redis 缓存,JVM 相关&#xf…

回归预测 | MATLAB实现SSA-DBN麻雀算法优化深度置信网络的数据多输入单输出回归预测

回归预测 | MATLAB实现SSA-DBN麻雀算法优化深度置信网络的数据多输入单输出回归预测 目录 回归预测 | MATLAB实现SSA-DBN麻雀算法优化深度置信网络的数据多输入单输出回归预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 基于麻雀算法优化深度置信网络(SSA-DB…

String、反射、枚举、lambda表达式以及泛型进阶(数据结构系列16)

目录 前言: 1. String 1.1 字符串常量池 1.1.1 创建对象的思考 1.1.2 字符串常量池(StringTable) 1.1.3 再谈String对象创建 1.1.4 intern方法 2. 反射 2.1 反射的定义 2.2 反射的用途 2.3 反射的基本信息 2.4 反射相关的类 2.4.…

网络安全、Web安全、渗透测试之笔经面经总结含答案

以下为网络安全各个方向涉及的面试题,星数越多代表问题出现的几率越大,祝各位都能找到满意的工作。 注:本套面试题,已整理成pdf文档,但内容还在持续更新中,因为无论如何都不可能覆盖所有的面试问题&#xf…

vue-antd-admin——关闭当前页面,跳转到指定页面——bus事件总线的用法

最近在写后台管理系统时,遇到一个需求: 关闭当前页面,然后跳转到指定页面。 具体实现方法如下: 1.tabsView.vue文件中添加bus文件,并实现跨组件之间的监听 1.1 引入bus文件 import Bus from /utils/bus; bus文件内…

解决npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher

一、问题 环境 系统:centos 7 node :v18.16.1 npm:9.5.1 安装pm2 npm install -g pm2提示报错: npm WARN deprecated uuid3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certai…

Redis高可用——主从复制

redis的主从复制 一、Redis 主从复制1.主从复制的作用:2.主从复制流程: 二、搭建Redis 主从复制1.安装 Redis①.环境准备②.修改内核参数③.安装redis④.创建redis工作目录⑤.环境变量⑥.定义systemd服务管理脚本 2.修改 Redis 配置文件(Mast…