【问题标题】:How to write a convolution multiplication in Android Renderscript?如何在 Android Renderscript 中编写卷积乘法?
【发布时间】:2012-04-10 14:23:41
【问题描述】:

我是 Android 渲染脚本的新手。 我需要在 RenderScript 中编写卷积乘法,因为最终应用程序将在 Android 上运行。数据流将是一个图像。 更具体地说,我无法使用 forEach 功能编写核心逻辑,虽然我可以在 Java 中完成,但速度太慢了! 请帮忙! 史蒂夫

【问题讨论】:

    标签: android convolution renderscript


    【解决方案1】:

    在 rsForEach 调用(或其他 Renderscript 函数)期间,您可以通过将原始图像分配绑定到 Renderscript 中的指针来访问原始图像(或您正在使用的任何类型的数据)的相邻像素,然后它可以作为数组访问。下面是一个基于 HelloCompute 示例的示例:

    #pragma version(1)
    #pragma rs java_package_name(com.android.example.hellocompute)
    
    rs_allocation gIn;
    rs_allocation gOut;
    rs_script gScript;
    
    static int mImageWidth;
    const uchar4 *gPixels;
    
    const float4 kWhite = {
        1.0f, 1.0f, 1.0f, 1.0f
    };
    const float4 kBlack = {
        0.0f, 0.0f, 0.0f, 1.0f
    };
    
    void init() {
    }
    
    static const int kBlurWidth = 20;
    static const float kMultiplier = 1.0f / (float)(kBlurWidth * 2 + 1);
    
    void root(const uchar4 *v_in, uchar4 *v_out, const void *usrData, uint32_t x, uint32_t y) {
        float4 original = rsUnpackColor8888(*v_in);
    
        float4 colour = original * kMultiplier;
    
        int y_component = mImageWidth * y;
    
        for ( int i = -kBlurWidth; i < 0; i++) {
            float4 temp_colour;
    
            if ( (int)x + i >= 0) {
                temp_colour = rsUnpackColor8888(gPixels[x+i + y_component]);
            }
            else {
                temp_colour = kWhite;
            }
    
            colour += temp_colour * kMultiplier;
        }
        for ( int i = 1; i <= kBlurWidth; i++) {
            float4 temp_colour;
    
            if ( x + i < mImageWidth) {
                temp_colour = rsUnpackColor8888(gPixels[x+i + y_component]);
            }
            else {
                temp_colour = kWhite;
            }
    
            colour += temp_colour * kMultiplier;
        }
    
        colour.a = 1.0f;
        *v_out = rsPackColorTo8888(colour);
    }
    
    
    void filter() {
        mImageWidth = rsAllocationGetDimX(gIn);
        rsDebug("Image size is ", rsAllocationGetDimX(gIn), rsAllocationGetDimY(gOut));
        rsForEach(gScript, gIn, gOut, NULL);
    }
    

    从以下 Java 调用。请注意对 mScript.bind_gPixels(mInAllocation) 的调用,它将原始图像数据绑定到 Renderscript 中的 gPixel 指针,因此使图像数据可作为数组使用。

        mRS = RenderScript.create(this);
    
        mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
                                                    Allocation.MipmapControl.MIPMAP_NONE,
                                                    Allocation.USAGE_SCRIPT);
        mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());
    
        mScript = new ScriptC_blur(mRS, getResources(), R.raw.blur);
    
        mScript.bind_gPixels(mInAllocation);
    
        mScript.set_gIn(mInAllocation);
        mScript.set_gOut(mOutAllocation);
        mScript.set_gScript(mScript);
        mScript.invoke_filter();
        mOutAllocation.copyTo(mBitmapOut);
    

    【讨论】:

    • 嗨,感谢您的代码,它运行良好;唯一的问题是 root() 在位图中按像素运行,对吗?无论如何我可以让 root() 在位图上按行/列运行,以便我可以利用那些快速模糊算法?
    • rsForEach 调用(执行 root())将在您传入的分配的每个元素上运行。您应该能够限制 rsForEach 调用操作的范围,但我很难做到这一点工作(见here)。
    • 虽然这可能不是你想要的。如果您想为每个图像行调用 root(),请创建一个分配,即类似于行图像数据的索引,并在其上调用 rsForEach。 root() 中的 data out 参数不能用于输出图像数据,因此您必须以与传入输入图像类似的方式传入输出图像分配,即在 RenderScript 中创建一个指针并绑定到它从 Java 方面。
    • 我的完整答案已在您的 related question 上结束
    猜你喜欢
    • 1970-01-01
    • 2018-05-03
    • 2013-06-19
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-17
    相关资源
    最近更新 更多