2011-01-05 18 views
13

Ich hämmere hier gegen eine Wand und ich bin ziemlich sicher, dass ich etwas Dummes mache, also Zeit, meine Dummheit öffentlich zu machen.Pixel aus zwei Bitmaps mischen

Ich versuche, zwei Bilder zu machen, mische sie zu einem dritten Bild mit Standard-Mischalgorithmen (Hardlight, Softlight, Overlay, Multiplizieren, etc).

Da Android solche Blend-Eigenschaften nicht integriert hat, habe ich den Pfad der einzelnen Pixel genommen und sie mit einem Algorithmus kombiniert. Die Ergebnisse sind jedoch Müll. Im Folgenden finden Sie die Ergebnisse einer einfachen Multiplikation (verwendete Bilder und erwartetes Ergebnis).

BASE: alt text

BLEND: alt text

Erwartetes Ergebnis: alt text

ABFALL ERGEBNIS: alt text

Jede Hilfe würde geschätzt. Unten ist der Code, den ich versucht habe, den ganzen "Müll" zu entfernen, aber einige haben es vielleicht geschafft. Ich werde es aufräumen, wenn etwas nicht klar ist.

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

Antwort

13

Nach der Wiedergabe, ich denke, Ihr Problem hat mit der Manipulation der Bilder im RGB565-Modus zu tun. Wie in this post diskutiert, müssen Bitmaps offenbar im ARGB8888-Modus sein, um richtig zu manipulieren. Ich habe zuerst das erwartete Ergebnis auf einer mehrfache Mischung durch folgende Maßnahmen:

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

Konvertieren der Bitmaps Modus zu ARGB8888 schien für mich zu arbeiten, zumindest mit den Gradienten Testmustern. Es können aber Sie brauchen nur Bildschirm oder Multiply zu tun, könnten Sie dies versuchen, so gut:

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

Damit Sie nicht die pro-Pixel-Berechnungen zu tun, aber Sie werden auf die voreingestellten PorterDuff.Mode s begrenzt. In meinen schnellen (und schmutzigen) Tests war dies die einzige Möglichkeit, mit der ich die Überblendung auf Nicht-Farbverlaufsbilder anwenden konnte.

+0

Kevin, danke für die Hilfe. Ich verwende keine Bilder mit Transparenz, daher ist die Deckkraft immer 1. Ich habe das Beispiel mit Bildern aktualisiert und den Code aufgeräumt. – MarkPowell

+0

Hmm danke für die Bilder - das ist wirklich ein Müllresultat. Ich habe momentan keinen Zugang zu einer Android-Entwicklungsumgebung, aber ich frage mich, ob es etwas mit der Pixeldichte der Bitmaps zu tun hat - es sieht so aus, als ob deine Bitmaps RGB565-Farbraum benutzen, aber es ist scheint aus der Dokumentation, die Farbe in ARGB4444 Raum arbeitet. Ich habe nicht alle Bitmap-/Farbdokumente analysiert, um zu sehen, wie/wenn diese Konvertierung automatisch durchgeführt wird, aber es könnte sich lohnen, sie auszuprobieren, bis ich einige Tests auf der tatsächlichen Plattform durchführen kann. –

+0

Okay, ich habe ein bisschen damit gespielt, und ich war in der Lage, Ihr "Müll" -Ergebnis zu reproduzieren, und ich habe es auf zwei verschiedene Arten arbeiten lassen.Ich werde versuchen, meine ursprüngliche Antwort zu ändern, um dies zu reflektieren. –

4

einfache Overlay Sie auf diese Weise tun können (der Einfachheit halber wird angenommen, dass BMP1 gleich oder größer als 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; 
} 

Für komplexere Mischalgorithmen, vielleicht haben Sie sich mit einigen helfen können verfügbare Bitmap/Canvas Funktionen.

+0

Danke, aber es ging diese Route und eine andere Diskussion, die mich zu der Annahme führte, dass komplexe Mischung nicht über Canvas möglich war. Dies führte dazu, dass ich versuchte, pro Pixel zu mischen. – MarkPowell