2011-01-05 22 views
13

Me estoy golpeando la cabeza contra una pared aquí, y estoy bastante seguro de que estoy haciendo algo estúpido, por lo que es hora de hacer pública mi estupidez.Mezclar píxeles de Dos mapas de bits

Estoy tratando de tomar dos imágenes, mezclarlas en una tercera imagen usando algoritmos de mezcla estándar (luz fuerte, luz suave, superposición, multiplicar, etc.).

Como Android no tiene esas propiedades de mezcla incorporadas, he ido por el camino de tomar cada píxel y combinarlos usando un algoritmo. Sin embargo, los resultados son basura. A continuación se muestran los resultados de una mezcla simple y múltiple (imágenes utilizadas y resultado esperado).

BASE: alt text

BLEND: RESULTADO alt text

ESPERADO: alt text

BASURA RESULTADO: alt text

sería apreciada Cualquier ayuda. A continuación está el código, que he tratado de eliminar toda la "basura", pero algunos pueden haberlo superado. Lo limpiaré si algo no está claro.

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; 
} 

Respuesta

13

Después de la reproducción, creo que su problema tiene que ver con la manipulación de las imágenes en modo RGB565. Como se discutió en this post, parece que los mapas de bits deben estar en modo ARGB8888 para manipularse correctamente. Llegué por primera vez el resultado esperado de una mezcla multiplican haciendo lo siguiente:

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... 

la conversión de los mapas de bits a modo de ARGB8888 parecen funcionar para mí, al menos con los patrones de prueba de gradiente. Sin embargo, sólo tiene que hacer de pantalla o múltiple, puede probar esto, así:

// 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); 

Con esto, usted no está haciendo los cálculos por píxel, sino que se limitan a los preestablecidos PorterDuff.Mode s. En mi prueba rápida (y sucia), esta fue la única forma en que pude hacer que la mezcla funcionara en imágenes que no son de gradiente.

+0

Kevin, gracias por la ayuda. No utilizo imágenes con transparencia, por lo que la opacidad siempre será 1. He actualizado el ejemplo con imágenes y he limpiado el código. – MarkPowell

+0

Hmm gracias por las imágenes, realmente es un resultado de basura. No tengo acceso a un entorno de desarrollo de Android en este momento, pero me pregunto si no tiene algo que ver con la densidad de píxeles de los mapas de bits: parece que tus mapas de bits están usando el espacio de color RGB565, pero parece de los documentos que Color funciona en el espacio ARGB4444. No he analizado todos los documentos de mapa de bits/color para ver cómo/si esta conversión se maneja automáticamente, pero podría valer la pena revisarla hasta que pueda hacer algunas pruebas en la plataforma real. –

+0

Muy bien, jugué un poco y pude reproducir su resultado de "basura", y lo hice funcionar de dos maneras diferentes.Trataré de cambiar mi respuesta original para reflejar esto. –

4

superposición simple que puede hacer de esta manera (por simplicidad se supone que BMP1 es igual o más grande que la BMP-2):

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; 
} 

Para algoritmos de fusión más complejas, tal vez usted puede ayudarse a sí mismo con un poco de funciones disponibles de mapa de bits/lienzo.

+0

Gracias, pero estaba yendo por esa ruta y otra discusión que me llevó a creer que la mezcla compleja no era posible a través del Canvas. Esto resultó en que intenté mezclar por pixel. – MarkPowell

Cuestiones relacionadas