Смешивание пикселей из двух растровых изображений
Я бил головой о стену здесь, и я уверен, что я делаю что-то глупое, так что время, чтобы сделать мою глупость публичной.
Я пытаюсь взять два изображения, объединить их в третье изображение, используя стандартные алгоритмы смешивания (Hardlight, softlight, overlay, multiply и т.д.).
Поскольку у Android нет таких свойств смешивания, я пошел по пути взятия каждого пикселя и объединил их с помощью алгоритма. Однако результатом является мусор. Ниже приведены результаты простой многократной комбинации (используемые изображения и ожидаемый результат).
BASE: ![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;
}
Ответы
Ответ 1
После воспроизведения, я думаю, что ваша проблема связана с управлением изображениями в режиме 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
s. В моем быстром (и грязном) тестировании это был единственный способ, которым я смог заставить смешение работать с неградиентными изображениями.
Ответ 2
Простое наложение вы можете сделать так (для простоты предполагается, что 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;
}
Для более сложных алгоритмов смешивания, возможно, вы можете помочь себе с некоторыми доступными функциями Bitmap/Canvas.