个人觉得libyuv性能更好,建议使用libyuv,地址:https://120.27.239.50/wordpress/index.php/2020/05/25/androidlibyuv/
好了,回到正题,先放Demo工程地址:https://github.com/bookzhan/YUVRenderScript.git
史上最强的YUV转换RenderScript,支持转换成RGBA,BGRA,并且同时支持旋转,翻转,YUV数据格式支持NV21, YV12, YUV420_888, 分别对应Android Camera1API 以及Camera2 API 的YUV处理
这段时间在做一些Android Camera数据处理的相关工作,涉及到YUV转RGBA的事情,由于对性能要求极高我先后采用了多种方案,最开始的时候是试用OpenCV里面的方法,最后发现性能不是很理想,最后又使用了libyuv,这个库性能要比OpenCV要好,对性能要求不是特别高的可以采用,这个库有一定的缺陷,YUV转换后图像还原度很不好,明显感觉到有色差,而且在Android手机上长时间运行,性能下降明显,最后没有办法了开始采用RenderScript,这里不得不吐槽一下Google 他仅仅提供了一个ScriptIntrinsicYuvToRGB,而且不支持YUV420_888,也不支持旋转,翻转,我呸渣男! 还能怎么办自己动手吧!
话不多说直接上代码吧(里面涉及到很多YUV的知识我就不讲了):
#pragma version(1)
#pragma rs java_package_name(com.luoye.bzyuv)
#pragma rs_fp_relaxed
rs_allocation mInput;
rs_allocation mInY;
rs_allocation mInU;
rs_allocation mInV;
rs_allocation mInNV21;
rs_allocation mInYV12;
int inWidth=0,inHeight=0;
int orientation=0;
bool flipY=false;
int uvPixelStride=1;
static uchar4 yuvToRGBA4(uchar y, uchar u, uchar v) {
short Y = ((short)y) - 16;
short U = ((short)u) - 128;
short V = ((short)v) - 128;
short4 p;
p.x = (Y * 298 + V * 409 + 128) >> 8;
p.y = (Y * 298 - U * 100 - V * 208 + 128) >> 8;
p.z = (Y * 298 + U * 516 + 128) >> 8;
p.w = 255;
if(p.x < 0) {
p.x = 0;
}
if(p.x > 255) {
p.x = 255;
}
if(p.y < 0) {
p.y = 0;
}
if(p.y > 255) {
p.y = 255;
}
if(p.z < 0) {
p.z = 0;
}
if(p.z > 255) {
p.z = 255;
}
return (uchar4){p.x, p.y, p.z, p.w};
}
static float4 yuvToRGBA_f4(uchar y, uchar u, uchar v) {
float4 yuv_U_values = {0.f, -0.392f * 0.003921569f, +2.02 * 0.003921569f, 0.f};
float4 yuv_V_values = {1.603f * 0.003921569f, -0.815f * 0.003921569f, 0.f, 0.f};
float4 color = (float)y * 0.003921569f;
float4 fU = ((float)u) - 128.f;
float4 fV = ((float)v) - 128.f;
color += fU * yuv_U_values;
color += fV * yuv_V_values;
color = clamp(color, 0.f, 1.f);
return color;
}
void makeRef(rs_allocation ay, rs_allocation au, rs_allocation av, rs_allocation aout) {
uint32_t w = rsAllocationGetDimX(ay);
uint32_t h = rsAllocationGetDimY(ay);
for (int y = 0; y < h; y++) {
//rsDebug("y", y);
for (int x = 0; x < w; x++) {
int py = rsGetElementAt_uchar(ay, x, y);
int pu = rsGetElementAt_uchar(au, x >> 1, y >> 1);
int pv = rsGetElementAt_uchar(av, x >> 1, y >> 1);
//rsDebug("py", py);
//rsDebug(" u", pu);
//rsDebug(" v", pv);
uchar4 rgb = yuvToRGBA4(py, pu, pv);
//rsDebug(" ", rgb);
rsSetElementAt_uchar4(aout, rgb, x, y);
}
}
}
void makeRef_f4(rs_allocation ay, rs_allocation au, rs_allocation av, rs_allocation aout) {
uint32_t w = rsAllocationGetDimX(ay);
uint32_t h = rsAllocationGetDimY(ay);
for (int y = 0; y < h; y++) {
//rsDebug("y", y);
for (int x = 0; x < w; x++) {
uchar py = rsGetElementAt_uchar(ay, x, y);
uchar pu = rsGetElementAt_uchar(au, x >> 1, y >> 1);
uchar pv = rsGetElementAt_uchar(av, x >> 1, y >> 1);
//rsDebug("py", py);
//rsDebug(" u", pu);
//rsDebug(" v", pv);
float4 rgb = yuvToRGBA_f4(py, pu, pv);
//rsDebug(" ", rgb);
rsSetElementAt_float4(aout, rgb, x, y);
}
}
}
static void setLocation(int x,int y, int*targetX,int *targetY){
int finalX=x;
int finalY=y;
if(orientation!=0){
if(orientation==90){
finalX=y;
finalY=inHeight-1-x;
if(flipY){
finalX=inWidth-1-finalX;
}
}else if(orientation==180){
finalX=inWidth - 1 - x;
finalY=inHeight - 1 - y;
if(flipY){
finalY=inHeight-1-finalY;
}
}else if(orientation==270){
finalX=inWidth - 1 - y;
finalY=x;
if(flipY){
finalY=inHeight-1-finalY;
}
}
}else{
if(flipY){
finalY=inHeight-1-finalY;
}
}
*targetX=finalX;
*targetY=finalY;
}
uchar4 __attribute__((kernel)) yuv_420_888_2_rgba(uint32_t x, uint32_t y) {
if(inWidth<=0||inHeight<=0){
rsDebug("bz_inWidth<=0||inHeight<=0", inWidth,inHeight);
return '0';
}
int targetX=x;
int targetY=y;
setLocation(x,y,&targetX,&targetY);
uint uvIndex= uvPixelStride * (targetX/2) + inWidth*(targetY/2);
uchar yps= rsGetElementAt_uchar(mInY,targetX,targetY);
uchar u= rsGetElementAt_uchar(mInU,uvIndex);
uchar v= rsGetElementAt_uchar(mInV,uvIndex);
return yuvToRGBA4(yps, u, v);
}
uchar4 __attribute__((kernel)) yuv_420_888_2_bgra(uint32_t x, uint32_t y) {
if(inWidth<=0||inHeight<=0){
rsDebug("bz_inWidth<=0||inHeight<=0", inWidth,inHeight);
return '0';
}
int targetX=x;
int targetY=y;
setLocation(x,y,&targetX,&targetY);
uint uvIndex= uvPixelStride * (targetX/2) + inWidth*(targetY/2);
uchar yps= rsGetElementAt_uchar(mInY,targetX,targetY);
uchar u= rsGetElementAt_uchar(mInU,uvIndex);
uchar v= rsGetElementAt_uchar(mInV,uvIndex);
uchar4 rgba= yuvToRGBA4(yps, u, v);
return (uchar4){rgba.z, rgba.y, rgba.x,rgba.w};
}
uchar4 __attribute__((kernel)) yuv_yv12_2_rgba(uint32_t x, uint32_t y) {
if(inWidth<=0||inHeight<=0){
rsDebug("bz_inWidth<=0||inHeight<=0", inWidth,inHeight);
return '0';
}
int targetX=x;
int targetY=y;
setLocation(x,y,&targetX,&targetY);
uint yIndex=targetX+inWidth*targetY;
uint uIndex=inWidth*inHeight+ (targetX/2) + inWidth/2*(targetY/2);
uint vIndex=inWidth*inHeight+inWidth*inHeight/4+ (targetX/2) + inWidth/2*(targetY/2);
uchar yps= rsGetElementAt_uchar(mInYV12,yIndex);
uchar u= rsGetElementAt_uchar(mInYV12,uIndex);
uchar v= rsGetElementAt_uchar(mInYV12,vIndex);
return yuvToRGBA4(yps, v, u);
}
uchar4 __attribute__((kernel)) yuv_yv12_2_bgra(uint32_t x, uint32_t y) {
if(inWidth<=0||inHeight<=0){
rsDebug("bz_inWidth<=0||inHeight<=0", inWidth,inHeight);
return '0';
}
int targetX=x;
int targetY=y;
setLocation(x,y,&targetX,&targetY);
uint yIndex=targetX+inWidth*targetY;
uint uIndex=inWidth*inHeight+ (targetX/2) + inWidth/2*(targetY/2);
uint vIndex=inWidth*inHeight+inWidth*inHeight/4+ (targetX/2) + inWidth/2*(targetY/2);
uchar yps= rsGetElementAt_uchar(mInYV12,yIndex);
uchar u= rsGetElementAt_uchar(mInYV12,uIndex);
uchar v= rsGetElementAt_uchar(mInYV12,vIndex);
uchar4 rgba= yuvToRGBA4(yps, v, u);
return (uchar4){rgba.z, rgba.y, rgba.x,rgba.w};
}
uchar4 __attribute__((kernel)) yuv_nv21_2_rgba(uint32_t x, uint32_t y) {
if(inWidth<=0||inHeight<=0){
rsDebug("bz_inWidth<=0||inHeight<=0", inWidth,inHeight);
return '0';
}
int targetX=x;
int targetY=y;
setLocation(x,y,&targetX,&targetY);
uint yIndex=targetX+inWidth*targetY;
uint uIndex=inWidth*inHeight+ 2*(targetX/2) + inWidth*(targetY/2);
uint vIndex=inWidth*inHeight+ 2*(targetX/2) + inWidth*(targetY/2)+1;
uchar yps= rsGetElementAt_uchar(mInNV21,yIndex);
uchar u= rsGetElementAt_uchar(mInNV21,uIndex);
uchar v= rsGetElementAt_uchar(mInNV21,vIndex);
return yuvToRGBA4(yps, v, u);
}
uchar4 __attribute__((kernel)) yuv_nv21_2_bgra(uint32_t x, uint32_t y) {
if(inWidth<=0||inHeight<=0){
rsDebug("bz_inWidth<=0||inHeight<=0", inWidth,inHeight);
return '0';
}
int targetX=x;
int targetY=y;
setLocation(x,y,&targetX,&targetY);
uint yIndex=targetX+inWidth*targetY;
uint uIndex=inWidth*inHeight+ 2*(targetX/2) + inWidth*(targetY/2);
uint vIndex=inWidth*inHeight+ 2*(targetX/2) + inWidth*(targetY/2)+1;
uchar yps= rsGetElementAt_uchar(mInNV21,yIndex);
uchar u= rsGetElementAt_uchar(mInNV21,uIndex);
uchar v= rsGetElementAt_uchar(mInNV21,vIndex);
uchar4 rgba= yuvToRGBA4(yps, v, u);
return (uchar4){rgba.z, rgba.y, rgba.x,rgba.w};
}
float4 __attribute__((kernel)) cvt_f4(uint32_t x, uint32_t y) {
uchar py = rsGetElementAtYuv_uchar_Y(mInput, x, y);
uchar pu = rsGetElementAtYuv_uchar_U(mInput, x, y);
uchar pv = rsGetElementAtYuv_uchar_V(mInput, x, y);
//rsDebug("py2", py);
//rsDebug(" u2", pu);
//rsDebug(" v2", pv);
return rsYuvToRGBA_float4(py, pu, pv);
}
The supported methods are as follows:
- yuv_yv12_2_Bitmap
- yuv_yv12_2_RGBA
- yuv_yv12_2_BGRA
- yuv_nv21_2_Bitmap
- yuv_nv21_2_RGBA
- yuv_nv21_2_BGRA
- yuv420_2_Bitmap
- yuv420_2_RGBA
- yuv420_2_BGRA
нло информация iphone информация https://opjgrotip.com казахстан информация
Pingback引用通告: Android YUV转换,支持Camera1,Camera2 | 绕云技术笔记
1、在Camera2Activity中onImageAvailable,u和v数据错位了:
if (null == yBuffer) {
yBuffer = new byte[width * height];
}
if (null == uBuffer) {
uBuffer = new byte[planes[1].getBuffer().capacity()];
}
if (null == vBuffer) {
vBuffer = new byte[planes[2].getBuffer().capacity()];
}
planes[0].getBuffer().get(yBuffer);
planes[1].getBuffer().get(vBuffer);
planes[2].getBuffer().get(uBuffer);
2、在YuvConvertUtil的convertYuv420中,U,V数据也错位:
scriptC_yuv.set_mInU(vIn);
scriptC_yuv.set_mInV(uIn);
3、运行,把YUV420_8888的数据转化为RGB,图片失去颜色变成会灰度图
我在我手机上试了一下,没有问题,这个工程就不支持转换成RGB, 只是支持转换成RGBA, 也有可能是你手机上的兼容问题RowStride大小不一样导致的,现阶段不打算做支持了,建议你用这个工程https://120.27.239.50/wordpress/index.php/2020/05/25/androidlibyuv/,效果性能更好