Смешивание пикселей из двух растровых изображений - PullRequest
15 голосов
/ 05 января 2011

Я бью себя головой об стену, и я вполне уверен, что делаю что-то глупое, так что пора обнародовать мою глупость.

Я пытаюсь взять два изображения, смешать их вместе в третье изображение, используя стандартные алгоритмы наложения (Hardlight, softlight, overlay, multiply и т. Д.).

Поскольку в Android нет таких встроенных свойств наложения, я пошел по пути, отбирая каждый пиксель и комбинируя их, используя алгоритм. Тем не менее, результаты являются мусором. Ниже приведены результаты простого умножения (использованные изображения и ожидаемый результат).

БАЗА: alt text

BLEND: alt text

ОЖИДАЕМЫЙ РЕЗУЛЬТАТ: alt text

РЕЗУЛЬТАТ ГАРАЖА: alt text

Любая помощь будет оценена. Ниже приведен код, который я пытался убрать из «мусора», но некоторые, возможно, сделали это. Я уберу это, если что-то не ясно.

    ImageView imageView = (ImageView) findViewById(R.id.ImageView01);
    Bitmap base = BitmapFactory.decodeResource(getResources(), R.drawable.base);
    Bitmap result = base.copy(Bitmap.Config.RGB_565, true);
    Bitmap blend = BitmapFactory.decodeResource(getResources(), R.drawable.blend);

    IntBuffer buffBase = IntBuffer.allocate(base.getWidth() * base.getHeight());
    base.copyPixelsToBuffer(buffBase);
    buffBase.rewind();

    IntBuffer buffBlend = IntBuffer.allocate(blend.getWidth() * blend.getHeight());
    blend.copyPixelsToBuffer(buffBlend);
    buffBlend.rewind();

    IntBuffer buffOut = IntBuffer.allocate(base.getWidth() * base.getHeight());
    buffOut.rewind();

    while (buffOut.position() < buffOut.limit()) {
        int filterInt = buffBlend.get();
        int srcInt = buffBase.get();

        int redValueFilter = Color.red(filterInt);
        int greenValueFilter = Color.green(filterInt);
        int blueValueFilter = Color.blue(filterInt);

        int redValueSrc = Color.red(srcInt);
        int greenValueSrc = Color.green(srcInt);
        int blueValueSrc = Color.blue(srcInt);

        int redValueFinal = multiply(redValueFilter, redValueSrc);
        int greenValueFinal = multiply(greenValueFilter, greenValueSrc);
        int blueValueFinal = multiply(blueValueFilter, blueValueSrc);

        int pixel = Color.argb(255, redValueFinal, greenValueFinal, blueValueFinal);

        buffOut.put(pixel);
    }

    buffOut.rewind();

    result.copyPixelsFromBuffer(buffOut);   

    BitmapDrawable drawable = new BitmapDrawable(getResources(), result);
    imageView.setImageDrawable(drawable);
}

int multiply(int in1, int in2) {
    return in1 * in2 / 255;
}

Ответы [ 2 ]

15 голосов
/ 05 января 2011

После воспроизведения, я думаю, что ваша проблема связана с манипулированием изображениями в режиме RGB565. Как обсуждалось в этом посте , битовые карты, по-видимому, должны быть в режиме ARGB8888 для правильной манипуляции. Сначала я получил ожидаемый результат для смешанного смешивания, выполнив следующее:

Resources res = getResources();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap base = BitmapFactory.decodeResource(res, R.drawable.base, options);
Bitmap blend = BitmapFactory.decodeResource(res, R.drawable.blend, options);

// now base and blend are in ARGB8888 mode, which is what you want

Bitmap result = base.copy(Config.ARGB_8888, true);
// Continue with IntBuffers as before...

Преобразование растровых изображений в режим ARGB8888, похоже, действительно работает для меня, по крайней мере с тестовыми шаблонами градиента. Однако, если вам нужно только сделать Screen или Multiply, вы также можете попробовать это:

// Same image creation/reading as above, then:
Paint p = new Paint();
p.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
p.setShader(new BitmapShader(blend, TileMode.CLAMP, TileMode.CLAMP));

Canvas c = new Canvas();
c.setBitmap(result);
c.drawBitmap(base, 0, 0, null);
c.drawRect(0, 0, base.getWidth(), base.getHeight(), p);

При этом вы не выполняете расчеты для каждого пикселя, но вы ограничены предустановленными PorterDuff.Mode с. В моем быстром (и грязном) тестировании это был единственный способ заставить смешивание работать с неградиентными изображениями.

5 голосов
/ 05 января 2011

Простое наложение вы можете сделать таким образом (для простоты предполагается, что bmp1 равен или больше, чем bmp2):

private Bitmap bitmapOverlay(Bitmap bmp1, Bitmap bmp2) 
{ 
    Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig()); 
    Canvas canvas = new Canvas(bmOverlay); 
    canvas.drawBitmap(bmp1, 0, 0, null);
    canvas.drawBitmap(bmp2, 0, 0, null);
    return bmOverlay; 
} 

Для более сложных алгоритмов наложения, возможно, вы можете помочь себе с некоторыми доступными растровыми изображениями/ Функции холста.

...