Frage Pixel aus zwei Bitmaps mischen


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

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

Da in Android keine solchen Blend-Eigenschaften integriert sind, habe ich den Pfad zur Aufnahme jedes Pixels und zur Kombination mit einem Algorithmus gewählt. Die Ergebnisse sind jedoch Müll. Im Folgenden finden Sie die Ergebnisse einer einfachen Multiplikation (verwendete Bilder und erwartetes Ergebnis).

BASE: alt text

MISCHUNG: alt text

ERWARTETES ERGEBNIS: alt text

GUTACHTEN ERGEBNIS: alt text

Jede Hilfe wäre willkommen. 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;
}

14
2018-01-05 14:44


Ursprung


Antworten:


Nach der Wiedergabe denke ich, dass dein Problem mit der Manipulation der Bilder im RGB565-Modus zu tun hat. Wie in dieser BeitragBitmaps müssen offensichtlich im ARGB8888-Modus sein, um richtig zu manipulieren. Ich habe zuerst das erwartete Ergebnis einer Multiplikation erhalten, indem ich Folgendes getan habe:

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

Das Konvertieren der Bitmaps in den ARGB8888-Modus schien mir zumindest bei den Gradienten-Testmustern zu funktionieren. Allerdings müssen Sie nur Screen oder Multiply durchführen, das können Sie auch versuchen:

// 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 werden keine Berechnungen pro Pixel durchgeführt, Sie sind jedoch auf das Preset beschränkt PorterDuff.Modes. In meinen schnellen (und schmutzigen) Tests war dies die einzige Möglichkeit, mit der ich die Überblendung auf Nicht-Farbverlaufsbilder anwenden konnte.


14
2018-01-05 18:32



Einfache Überlagerung kann man so machen (der Einfachheit halber wird angenommen, dass bmp1 gleich oder größer als bmp2 ist):

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

Bei komplexeren Mischalgorithmen können Sie sich vielleicht mit einigen verfügbaren Bitmap / Canvas-Funktionen behelfen.


5
2018-01-05 16:49