Как написать умножение свертки в Android Renderscript?

Я новичок в Android Renderscript. Мне нужно написать умножение свертки в RenderScript, так как окончательное приложение будет работать на Android. Поток данных будет изображением. В частности, я не могу написать основную логику, используя функциональность forEach, хотя я могу сделать это на Java, но слишком медленно! Пожалуйста помоги! Стив


person user1324282    schedule 10.04.2012    source источник


Ответы (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), который связывает исходные данные изображения с указателем gPixel в Renderscript и, следовательно, делает данные изображения доступными в виде массива.

    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);
person Massycat    schedule 21.04.2012
comment
привет, спасибо за ваш код, и он работает хорошо; единственная проблема заключается в том, что root() выполняется для каждого пикселя в растровом изображении, верно? Могу ли я в любом случае запустить root() для каждой строки/столбца растрового изображения, чтобы я мог воспользоваться преимуществами этого быстрого алгоритма размытия? - person xandy; 13.05.2012
comment
Вызов rsForEach (выполняющий root()) будет выполняться для каждого элемента Allocation, который вы передаете. У вас должна быть возможность ограничить диапазон, в котором работает вызов rsForEach, но мне трудно заставить это работать (см. здесь). - person Massycat; 16.05.2012
comment
Хотя это, вероятно, не то, что вы хотите в любом случае. Если вы хотите, чтобы root() вызывался для каждой строки изображения, создайте выделение, которое представляет собой что-то вроде индексов данных изображения строки, и вызовите для этого rsForEach. Аргумент вывода данных внутри root() не может быть использован для вывода данных изображения, поэтому вам придется передать выделение выходного изображения аналогично передаче входного изображения, т.е. создать указатель внутри RenderScript и привязать к нему. со стороны Явы. - person Massycat; 16.05.2012
comment
Мой полный ответ на ваш связанный вопрос закончен. - person Massycat; 16.05.2012