Смешивание пикселей из двух растровых изображений

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

Я пытаюсь взять два изображения, объединить их в третье изображение, используя стандартные алгоритмы смешивания (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; } 

Solutions Collecting From Web of "Смешивание пикселей из двух растровых изображений"

После воспроизведения я думаю, что ваша проблема связана с управлением изображениями в режиме 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. В моем быстром (и грязном) тестировании это был единственный способ, которым я смог заставить смешение работать с неградиентными изображениями.

Простым наложением вы можете сделать этот путь (для простоты предполагается, что 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.