日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

ue4 android vulkan,在Android用vulkan完成蓝绿幕扣像

發(fā)布時間:2025/3/15 Android 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ue4 android vulkan,在Android用vulkan完成蓝绿幕扣像 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

效果圖(1080P處理)

因為攝像頭開啟自動曝光,畫面變動時,亮度變化導(dǎo)致扣像在轉(zhuǎn)動時如上。

這個demo主要測試二點,一是測試ndk camera集成效果,二是本項目對接外部實現(xiàn)的vulkan層是否方便,用于以后移植GPUImage里的實現(xiàn)。

我簡化了在android下vulkan與opengles紋理互通里的處理,沒有vulkan窗口與交換鏈這些邏輯,只用到vulkan compute shader計算管線得到結(jié)果然后交換給opengl里的紋理。

NDK Camera集成

主要參考 NdkCamera Sample的實現(xiàn),然后封裝成滿足Aoce定義設(shè)備接口。

說下遇到的坑。

AIMAGE_FORMAT_YUV_420_888 可能是YUV420P,也可能是NV12,需要在AImageReader_ImageListener里拿到image通過AImage_getPlanePixelStride里的UV的plan是否為1來判斷是否為YUV420P,或者看data[u]-data[y]=1來看是否為NV12.具體可以看getVideoFrame的實現(xiàn)。

AImageReader_new里的maxImages比較重要,簡單理解為預(yù)先申請幾張圖,這個值越大,顯示越平滑。

AImageReader_new如果不開線程,則圖像處理加到這個線程里,導(dǎo)致讀取圖像變慢。打開線程處理,

我用的Redmi K10 pro,可以讀40003000,在AImageReader_ImageListener回調(diào)不做特殊處理,如下錯誤。

首先是Unable to acquire a lockedBuffer, very likely client tries to lock more than.

可以看到,運(yùn)行四次后報的,就是我設(shè)的maxImages,通過比對代碼邏輯,應(yīng)該是AImageReader_new讀四次后,我還沒處理完一楨,沒有AImage_delete,也就讀不了數(shù)據(jù)了.

然后檢查 AImageReader_acquireNextImage 這個狀態(tài),不對不讀,然后繼續(xù)引發(fā)讀取不可用內(nèi)存問題,分析應(yīng)該是處理數(shù)據(jù)的亂序線程AImage_delete可能釋放別的處理線程上的image,然后處理圖像線程上加上lock_guard(mutex),不會引發(fā)問題,但是會導(dǎo)致每maxImages卡一下,可以理解,讀的線程快,處理的慢,后面想了下,直接讓thread.join,圖片讀取很大時慢(比不開線程要快很多,40003000快二倍多,平均45ms),但是平滑的,暫時先這樣,后面看能不能直接拿AImage的harderbuffer去處理,讓處理速度追上讀取速度。

Chroma Key

如上所說,項目對接外部實現(xiàn)的vulkan層是否方便,在這重新生成一個模塊aoce_vulkan_extra,在這我選擇UE4 Matting里的邏輯來測試,因為這個邏輯非常簡單,也算讓我對手機(jī)的性能有個初步的了解。

首先把相關(guān)邏輯整理下,UE4上有相關(guān)節(jié)點,看下實現(xiàn)整理成glsl compute shader實現(xiàn)。

#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 控制亮度的強(qiáng)度系數(shù)

float lumaMask;

float chromaColorX;

float chromaColorY;

float chromaColorZ;

// 用環(huán)境光補(bǔ)受藍(lán)綠幕影響的像素(簡單理解扣像結(jié)果要放入的環(huán)境光的顏色)

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));

// 亮度指數(shù)

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);

// 亮度系數(shù)

vec3 lumaFactor = vec3(0.3f,0.59f,0.11f);

// 添加環(huán)境光收益

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));

}

這里面代碼最后倒數(shù)第二句實現(xiàn)混合背景時去掉,在這只是為了顯示查看效果。

然后引用aoce_vulkan里給的基類VkLayer,根據(jù)接口完成本身具體實現(xiàn),相關(guān)VkChromKeyLayer的實現(xiàn)可以說是非常簡單,至少我認(rèn)為達(dá)到我想要的方便。

還是一樣,先說遇到的坑,

開始在glsl中的UBO,我特意把一個float,vec3放一起,想當(dāng)然的認(rèn)為是按照vec4排列,這里注意,vec3不管前后接什么,大部分結(jié)構(gòu)定義下,都至少占vec4,所以后面為了和C++結(jié)構(gòu)align一樣,全部用float.

層啟用/不啟用會導(dǎo)致整個運(yùn)算graph重置,一般情況下,運(yùn)算線程與結(jié)果輸出線程不在一起,在重置時,運(yùn)算線程相關(guān)資源會重新生成,而此時輸出線程還在使用相關(guān)資源就會導(dǎo)致device lost錯誤,在這使用VkEvent用來表示是否在資源重置中。

然后就是與android UI層對接,android的UI沒怎么用過,丑也就先這樣吧。

總結(jié)

以上是生活随笔為你收集整理的ue4 android vulkan,在Android用vulkan完成蓝绿幕扣像的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。