在Android用vulkan完成蓝绿幕扣像
效果图(1080P处理)

因为摄像头开启自动曝光,画面变动时,亮度变化导致扣像在转动时如上。
源码地址vulkan_extratest
这个demo主要测试二点,一是测试ndk camera集成效果,二是本项目对接外部实现的vulkan层是否方便,用于以后移植GPUImage里的实现。
我简化了在android下vulkan与opengles纹理互通里的处理,没有vulkan窗口与交换链这些逻辑,只用到vulkan compute shader计算管线得到结果然后交换给opengl里的纹理。
NDK Camera集成
主要参考 NdkCamera Sample的实现,然后封装成满足Aoce定义设备接口。
说下遇到的坑。
AIMAGE_FORMAT_YUV_420_888 可能是YUV420P,也可能是NV12,需要在AImageReader_ImageListener里拿到image通过AImage_getPlanePixelStride里的UV的plan是否为1来判断是否为YUV420P,或者看data[u]-data[y]=1来看是否为NV12.具体可以看getVideoFrame的实现。
AImageReader_new里的maxImages比较重要,简单理解为预先申请几张图,这个值越大,显示越平滑。
AImageReader_new如果不开线程,则图像处理加到这个线程里,导致读取图像变慢。打开线程处理,
我用的Redmi K10 pro,可以读40003000,在AImageReader_ImageListener回调不做特殊处理,如下错误。
首先是Unable to acquire a lockedBuffer, very likely client tries to lock more than.
可以看到,运行四次后报的,就是我设的maxImages,通过比对代码逻辑,应该是AImageReader_new读四次后,我还没处理完一桢,没有AImage_delete,也就读不了数据了.
然后检查 AImageReader_acquireNextImage 这个状态,不对不读,然后继续引发读取不可用内存问题,分析应该是处理数据的乱序线程AImage_delete可能释放别的处理线程上的image,然后处理图像线程上加上lock_guard(mutex),不会引发问题,但是会导致每maxImages卡一下,可以理解,读的线程快,处理的慢,后面想了下,直接让thread.join,图片读取很大时慢(比不开线程要快很多,40003000快二倍多,平均45ms),但是平滑的,暂时先这样,后面看能不能直接拿AImage的harderbuffer去处理,让处理速度追上读取速度。
Chroma Key
如上所说,项目对接外部实现的vulkan层是否方便,在这重新生成一个模块aoce_vulkan_extra,在这我选择UE4 Matting里的逻辑来测试,因为这个逻辑非常简单,也算让我对手机的性能有个初步的了解。
首先把相关逻辑整理下,UE4上有相关节点,看下实现整理成glsl compute shader实现。
#version 450
// https://www.unrealengine.com/en-US/tech-blog/setting-up-a-chroma-key-material-in-ue4
layout (local_size_x = 16, local_size_y = 16) in;// gl_WorkGroupSize
layout (binding = 0, rgba8) uniform readonly image2D inTex;
layout (binding = 1, rgba8) uniform image2D outTex;
layout (std140, binding = 2) uniform UBO {
// 0.2 控制亮度的强度系数
float lumaMask;
float chromaColorX;
float chromaColorY;
float chromaColorZ;
// 用环境光补受蓝绿幕影响的像素(简单理解扣像结果要放入的环境光的颜色)
float ambientScale;
float ambientColorX;
float ambientColorY;
float ambientColorZ;
// 0.4
float alphaCutoffMin;
// 0.5
float alphaCutoffMax;
float alphaExponent;
// 0.8
float despillCuttofMax;
float despillExponent;
} ubo;
const float PI = 3.1415926;
vec3 extractColor(vec3 color,float lumaMask){
float luma = dot(color,vec3(1.0f));
// 亮度指数
float colorMask = exp(-luma*2*PI/lumaMask);
// color*(1-colorMask)+color*luma
color = mix(color,vec3(luma),colorMask);
// 生成基于亮度的饱和度图
return color / dot(color,vec3(2.0));
}
void main(){
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(outTex);
if(uv.x >= size.x || uv.y >= size.y){
return;
}
vec3 inputColor = imageLoad(inTex,uv).rgb;
vec3 chromaColor = vec3(ubo.chromaColorX,ubo.chromaColorY,ubo.chromaColorZ);
vec3 ambientColor = vec3(ubo.ambientColorX,ubo.ambientColorY,ubo.ambientColorZ);
vec3 color1 = extractColor(chromaColor,ubo.lumaMask);
vec3 color2 = extractColor(inputColor,ubo.lumaMask);
vec3 subColor = color1 - color2;
float diffSize = length(subColor);
float minClamp = diffSize-ubo.alphaCutoffMin;
float dist = ubo.alphaCutoffMax - ubo.alphaCutoffMin;
// 扣像alpha
float alpha= clamp(pow(max(minClamp/dist,0),ubo.alphaExponent),0.0,1.0);
// 受扣像背景影响的颜色alpha
float inputClamp = ubo.despillCuttofMax - ubo.alphaCutoffMin;
float despillAlpha = 1.0f- clamp(pow(max(minClamp/inputClamp,0),ubo.despillExponent),0.0,1.0);
// 亮度系数
vec3 lumaFactor = vec3(0.3f,0.59f,0.11f);
// 添加环境光收益
vec3 dcolor = inputColor*lumaFactor*ambientColor*ubo.ambientScale*despillAlpha;
// 去除扣像背景
dcolor -= inputColor*chromaColor*despillAlpha;
dcolor += inputColor;
// 为了显示查看效果,后面屏蔽
dcolor = inputColor*alpha + ambientColor*(1.0-alpha);
imageStore(outTex,uv,vec4(dcolor,alpha));
}
这里面代码最后倒数第二句实现混合背景时去掉,在这只是为了显示查看效果。
然后引用aoce_vulkan里给的基类VkLayer,根据接口完成本身具体实现,相关VkChromKeyLayer的实现可以说是非常简单,至少我认为达到我想要的方便。
还是一样,先说遇到的坑,
开始在glsl中的UBO,我特意把一个float,vec3放一起,想当然的认为是按照vec4排列,这里注意,vec3不管前后接什么,大部分结构定义下,都至少占vec4,所以后面为了和C++结构align一样,全部用float.
层启用/不启用会导致整个运算graph重置,一般情况下,运算线程与结果输出线程不在一起,在重置时,运算线程相关资源会重新生成,而此时输出线程还在使用相关资源就会导致device lost错误,在这使用VkEvent用来表示是否在资源重置中。
然后就是与android UI层对接,android的UI没怎么用过,丑也就先这样吧。
在Android用vulkan完成蓝绿幕扣像的更多相关文章
- 一文读懂蓝绿发布、A/B 测试和金丝雀发布的优缺点
作者 | 扬少 背景 目前,业界已经总结出了几种常见的服务发布策略来解决版本升级过程中带来的流量有损问题.本文首先会对这些普遍的发布策略进行简单的原理解析,最后结合阿里云的云原生网关对这些发布策略进行 ...
- AI目标分割能力,无需绿幕即可实现快速视频抠图
绿幕抠图是影视制作过程中常见的技术手段,常用于视频中抠除并替换背景,通过后期加工实现视频剪辑制作的更多可能性.然而,绿幕抠图技术制作成本费时费力,无法应用于日常生活. 华为视频编辑服务近期上线目标分割 ...
- Kubernetes 中的渐进式交付:蓝绿部署和金丝雀部署
渐进式交付是持续交付的下一步, 它将新版本部署到用户的一个子集,并在将其滚动到全部用户之前对其正确性和性能进行评估, 如果不匹配某些关键指标,则进行回滚. 这里有一些有趣的项目,使得渐进式交付在 Ku ...
- 蓝绿部署、红黑部署、AB测试、灰度发布、金丝雀发布、滚动发布的概念与区别(转)
出处:https://www.baidu.com/link?url=QjboallwNm_jxcL3fHG57wEakiBfAs_3-TChTGu1eBXstlHEsGBc-NDA7AKTqsiroB ...
- OpenShift蓝绿及灰度部署
内容转自https://blog.csdn.net/jj_tyro/article/details/80136316, 并不断补充,感谢作者. 1.蓝绿部署 蓝绿部署实现的是全流量切换,适合于在测试完 ...
- Contour 学习笔记(二):使用级联功能实现蓝绿部署和金丝雀发布
上篇文章介绍了 Contour 分布式架构的工作原理,顺便简单介绍了下 IngressRoute 的使用方式.本文将探讨 IngressRoute 更高级的用法,其中级联功能是重点. 1. Ingre ...
- istio1.0 实现蓝绿发布(未完成)
istio1.0 实现蓝绿发布 环境: 192.168.0.91 master 192.168.0.92 node 第一步:安装k8s集群,参照:https://www.cnblogs.com/eff ...
- 蓝绿部署、A/B测试以及灰度发布(金丝雀发布)
过去的10多年里,很多大公司都在使用蓝绿部署,安全.可靠是这种部署方式的特点.蓝绿部署虽然算不上”Sliver Bullet“,但确实很实用.在有关于“微服务”.“DevOps”.“Cloud-nat ...
- 持续部署入门:基于 Kubernetes 实现蓝绿发布
前言 软件世界比以往任何时候都更快.为了保持竞争力,需要尽快推出新的软件版本,而不会中断活跃用户访问,影响用户体验.越来越多企业已将其应用迁移到 Kubernetes. 在 Kubernetes 中有 ...
随机推荐
- shellSyntax.md
shell #! /bin/bash 头文件 echo -e 若字符串出现特殊字符,则特别处理 -n 不要在最后自动换行 ./filename.sh sh filename.sh r ...
- 这么优雅的Java ORM没见过吧!
Java的ORM框架有很多,但由于Java语言的限制大部分都不够优雅也不够简单,所以作者只能另辟蹊径造轮子了.照旧先看示例代码了解个大概,然后再解释实现原理. 一.ORM示例 1. Insert ...
- HP PROLIANT DL388 GEN10 (故障3019)SPP损坏
HP PROLIANT DL388 GEN10 (故障3019)SPP损坏 1. 开机硬件自检,提示错误ERROR 3019: 2. 根据服务器版本GEN10下载最新固件SPP,可找服务商或者HP售后 ...
- LeetCode144 二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? /** * Defin ...
- MongoDB Sharding(二) -- 搭建分片集群
在上一篇文章中,我们基本了解了分片的概念,本文将着手实践,进行分片集群的搭建 首先我们再来了解一下分片集群的架构,分片集群由三部分构成: mongos:查询路由,在客户端程序和分片之间提供接口.本次实 ...
- 【Linux】扩大swap分区
今天安装oracle的时候,提示我swap分区过小.需要最少3g以上 但是安装系统了,想要扩大swap分区怎么办呢 下面来介绍如何扩大swap分区 按步骤介绍 Red Hat linux 如何增加sw ...
- 【Oracle】Script to Collect DRM Information (drmdiag.sql) (文档 ID 1492990.1)
脚本对应如下: The following (drmdiag.sql) is a script to collect information related to DRM (Dyanamic Reso ...
- Log4j日志记录
1.导入log4j的jar包 2.写log4j.properties文件,配置日志记录参数,一般参数如下所示: 第二行指定了输出日志的目录,此处用的相对路径,也可换成绝对路径: 第三行指定了输出的记录 ...
- ctfhub技能树—文件上传—前端验证
打开靶机 查看页面信息 尝试直接上传一句话木马 提示不允许上传 查看源码 发现仅允许上传.jpg,.png,.gif三种格式的文件 上传shell.jpg并使用burpsuite抓取数据包 添加完成后 ...
- 2V升5V的升压芯片,两款芯片电路图
2V的输入电压,是可以用来做5V输出的升压电路,但是2V的供电设备很少,不知道还有什么东西是2V电压的,还需要升压到5V的电路系统. 两款2V升5V的芯片电路图: 第1, PW5100升压芯片,输出电 ...