我尝试使用renderscript中的ScriptIntrinsicYuvToRGB类来进行YUV到RGB的转换,其中source是YUV420格式。 我有3个原始平面,我从文件中读取并尝试将它们提供给YUV类型的分配,并通过ScriptIntrinsicYuvToRGB.forEach传递它。
它正确地转换亮度(Y平面),但在颜色上失败,因为色度通道似乎从buf [w * h]位置读取所有值 - 请参阅代码示例中的注释部分。当Allocation没有正确处理UV平面时,它看起来像bug。我假设是因为我在分配时使用rsGetElementAtYuv_uchar_U
函数在脚本中进行了测试,并为任何坐标提供了相同的值(来自buf [w * h])。
我搜索了所有地方,如果我可以进一步指定YUV格式,例如步幅/偏移等,但没有找到设置Element.DataKind.PIXEL_YUV
和Type.Builder.setYuvFormat(ImageFormat.YUV_420_888)
的更多内容。
有人可以帮忙吗?
{
int w = 320, h = 172;
ScriptIntrinsicYuvToRGB yc = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
{
Element elemYUV = Element.createPixel(rs, Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV);
Type typeYUV = new Type.Builder(rs, elemYUV).setX(w).setY(h).setYuvFormat(ImageFormat.YUV_420_888).create();
Allocation yuv = Allocation.createTyped(rs, typeYUV);
byte[] buf = new byte[yuv.getBytesSize()];
int offs = 0;
for(int i=0; i<3; i++){
int sz = w*h;
if(i>0)
sz /= 4;
InputStream is = new FileInputStream("/sdcard/yuv/"+(i==0 ? 'y' : i==1 ? 'u' : 'v'));
int n = is.read(buf, offs, sz);
if(n!=sz)
throw new AssertionError("!");
offs += sz;
is.close();
}
// buf[w*h] = 0x40;
yuv.copyFrom(buf);
yc.setInput(yuv);
}
Type outType = new Type.Builder(rs, Element.U8_4(rs)).setX(w).setY(h).create();
Allocation out = Allocation.createTyped(rs, outType);
yc.forEach(out);
int[] buf = new int[out.getBytesSize()/4];
out.copy1DRangeToUnchecked(0, w*h, buf);
bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
bm.setPixels(buf, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
iv.setImageBitmap(bm);
yc.destroy();
}
答案 0 :(得分:0)
我相信您的类型需要setYuvFormat()
。这是我用来构建分配的两行:
Type typeYUV = Type.Builder(rs, Element.YUV(rs)).setYuvFormat(ImageFormat.NV21).create();
Allocation yuv = Allocation.createSized(rs, typeYUV.element, width*height*3/2);
答案 1 :(得分:-1)
一种解决方案是只填写U8分配并在自定义脚本中自行编制索引:
#pragma rs_fp_relaxed
rs_allocation yuv_in;
uint32_t width;
uint32_t offset_to_u;
uint32_t offset_to_v;
uchar4 RS_KERNEL yuv_to_rgba(uint32_t x, uint32_t y) {
uint32_t index = y * width + x;
uint32_t uv_index = (y >> 1) * width + (x >> 1);
float Y = (float)rsGetElementAt_uchar(yuv_in, index);
float U = (float)rsGetElementAt_uchar(yuv_in, uv_index + offset_to_u);
float V = (float)rsGetElementAt_uchar(yuv_in, uv_index + offset_to_v);
float3 f_out;
f_out.r = Y + 1.403f * V;
f_out.g = Y - 0.344f * U - 0.714f * V;
f_out.b = Y + 1.770f * U;
f_out = clamp(f_out, 0.f, 255.f);
uchar4 out;
out.rgb = convert_uchar3(f_out);
out.a = 255;
return out;
}
的java:
sc.set_yuv_in(yuv_allocation);
sc.set_width(width);
sc.set_offset_to_u(width * height);
sc.set_offset_to_v(width * height + (width/2 * height/2));
sc.forEach_yuv_to_rba(out);
YUV_420_888更像是一种通用的YUV类型,用于从android中的其他YUV资源导入。我不认为有一种方法可以设置u / v平面的步幅/偏移值,使其对自定义转换有用。