从ARGB8888转换为RGB565的Renderscript转换

3
我收到的位图格式为 ARGB8888,但我需要通过一些只接受RGB565的算法进行处理。我想使用 Renderscript 将这个位图转换为新格式,但似乎分配进和分配出的大小应该是相等的(或兼容的)。 bitmapIn 类型为 ARGB_8888, bitmapOut 类型为 RGB_565。

导致此问题的原因是:android.renderscript.RSIllegalArgumentException: 分配类型为 PIXEL_RGBA,类型为 UNSIGNED_8 的 4 字节,传递的位图却是 RGB_565

Java:

public void convert(final Bitmap bitmapIn, Bitmap bitmapOut)
{
    mInAllocation = Allocation.createFromBitmap(mRS, bitmapIn, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
    Type.Builder tb = new Type.Builder(mRS, Element.RGB_565(mRS)).setX(bitmapIn.getWidth()).setY(bitmapOut.getWidth());
    mOutAllocation = Allocation.createTyped(mRS, tb.create());
    // Call custom method (not forEach_root) so we can have uchar4 in and uchar3 out
    mScript.forEach_convert(mInAllocation, mOutAllocation);
    mOutAllocation.copyTo(bitmapOut);
}

Renderscript:
// Convert to RGB565 by quantizing the individual channels
void convert(const uchar4* v_in, uchar3* v_out)
{
    v_out->x = v_in->x >> 3;
    v_out->y = v_in->y >> 2;
    v_out->z = v_in->z >> 3;
}

请注意,如果我将两个位图都设置为ARGB_8888,并在uchar4*上工作并仅复制alpha(w)通道,则会看到位图被修改。
我知道565等于16位,因此实际上更可能是一个uchar2,但它也与类型中的分配不兼容。
如何在Renderscript中执行此类型转换?
2个回答

4

我无法找到正确的Renderscript类型来处理RGB565图像,但是uint16_t可以使用(至少在Nexus S上)。如Tim Murray的答案中所述,您必须单独绑定输入或输出Allocation。

以下是执行转换的Renderscript代码,其中输入的RGB8888 Allocation被单独绑定,rsForEach在RGB565 Allocation上调用:

#pragma version(1)
#pragma rs java_package_name(uk.co.massycat.renderscriptfun.rsfun)

rs_allocation gInImage;

void root(const uint16_t *v_in, uint16_t *v_out, const void *usrData, uint32_t x, uint32_t y) {
    uint16_t colour = 0;

    const uchar4 *in_pixel = rsGetElementAt(gInImage, x, y);

    uint32_t red = in_pixel->r;
    uint32_t green = in_pixel->g;
    uint32_t blue = in_pixel->b;

    red >>= 3;
    green >>= 2;
    blue >>= 3;

    // red (5 bits)
    colour |= red << 11;
    // green (6 bits)
    colour |= green << 5;
    // blue (5 bits)
    colour |= blue << 0;
#if 0
    // red (5 bits)
    colour |= 0x0 << 11;
    // green (6 bits)
    colour |= 0x0 << 5;
    // blue (5 bits)
    colour |= 0x1f << 0;
#endif

    *v_out = colour;
}

void doWork( rs_script script, rs_allocation alloc_out) {
    rsForEach(script, alloc_out, alloc_out);
}

当在Java端对RGB565分配调用rsForEach时,你需要调用invoke_doWork脚本对象方法而不是forEach_root脚本对象方法,因为forEach_root调用会对RGB565分配进行类型检查,并抛出一个异常,提示它与U16不兼容。

以下是Java端的代码:

mInImageAllocation = Allocation.createFromBitmap(mRS, mInBitmap,
            Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
Type.Builder tb = new Type.Builder(mRS, Element.RGB_565(mRS)).setX(mInBitmap.getWidth()).setY(mInBitmap.getHeight());
mOutAllocation = Allocation.createTyped(mRS, tb.create());

mScript.set_gInImage(mInImageAllocation);

mScript.invoke_doWork(mScript, mOutAllocation);
Bitmap tmp_bitmap = Bitmap.createBitmap(mInBitmap.getWidth(), mInBitmap.getHeight(), Bitmap.Config.RGB_565);
mOutAllocation.copyTo(tmp_bitmap);

mAnImageView.setImageBitmap(tmp_bitmap);
mAnImageView.invalidate();

4

最简单的方法是只将输出分配给内核,而将输入分配绑定为rs_allocation。使用rsGetElementAt_uchar4访问分配,进行转换,并返回一个short。


我仍然遇到类型转换错误:RSRuntimeException: U16 类型不匹配!RS 函数:ushort attribute((kernel)) root(uint32_t x, uint32_t y) { return 65535; } Java:分配为 RGBA_8888,输出为 RGB_565,通过 mScript.set_in_allocation(mAllocationIn) 进行绑定。 - BCL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接