2011-01-05 21 views
13

Tutaj biję głową o ścianę i jestem prawie pewna, że ​​robię coś głupiego, więc mam czas, aby upublicznić moją głupotę.Mieszanie pikseli z dwóch bitmap

Próbuję zrobić dwa obrazy, połączyć je w trzeci obraz przy użyciu standardowych algorytmów mieszania (Hardlight, softlight, overlay, mnożenie itp.).

Ponieważ Android nie ma wbudowanych takich właściwości mieszania, przeszedłem ścieżką robienia każdego piksela i łączenia ich za pomocą algorytmu. Jednak wyniki są śmieci. Poniżej przedstawiono wyniki prostego mieszania wielokrotnego (użyte obrazy i oczekiwany wynik).

BASE: alt text

BLEND: alt text

Oczekiwane WYNIK: alt text

ŚMIECI WYNIK: alt text

Każda pomoc będzie mile widziane. Poniżej znajduje się kod, który próbowałem usunąć z "wszystkich śmieci", ale niektóre mogły się przedostać. Sprzątnę, jeśli coś nie jest jasne.

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

Odpowiedz

13

Po odtworzeniu, myślę, że twój problem dotyczy manipulowania obrazami w trybie RGB565. Jak omówiono w this post, bitmapy prawdopodobnie muszą być w trybie ARGB8888, aby poprawnie nimi manipulować. I pierwszy raz oczekiwanego rezultatu na wielowarstwowego mieszanki, wykonując następujące czynności:

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

Konwersja bitmapy do trybu ARGB8888 nie wydają się działać dla mnie, przynajmniej z tych wzorów testowych gradientu. Jednak to tylko trzeba zrobić ekran lub wielokrotnie, można spróbować także:

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

Z tym, że nie robią obliczenia na piksel, ale ograniczają się do zaprogramowanych PorterDuff.Mode s. W moich szybkich (i brudnych) testach był to jedyny sposób, w jaki udało mi się przekonwertować miksowanie do obrazów bez gradientów.

+0

Kevin, dzięki za pomoc. Nie używam obrazów z przezroczystością, więc nieprzezroczystość zawsze będzie 1. Zaktualizowałem przykład obrazami i wyczyściłem kod. – MarkPowell

+0

Hmm dzięki za zdjęcia - to naprawdę jest wynik śmieci. W tej chwili nie mam dostępu do środowiska programisty Androida, ale zastanawiam się, czy nie ma to nic wspólnego z gęstością pikseli map bitowych - wygląda na to, że Twoje mapy bitowe używają przestrzeni barw RGB565, ale to wydaje się z dokumentów, że Color działa w przestrzeni ARGB4444. Nie przeanalizowałem wszystkich dokumentów Bitmap/Colour, aby zobaczyć, jak/jeśli ta konwersja jest obsługiwana automatycznie, ale warto ją sprawdzić, dopóki nie będę mógł przeprowadzić testów na rzeczywistej platformie. –

+0

W porządku, trochę się z tym bawiłem i udało mi się odtworzyć wynik "śmieci" i udało mi się to na dwa różne sposoby.Spróbuję zmienić oryginalną odpowiedź, aby to odzwierciedlić. –

4

Prosta nakładka można zrobić w ten sposób (dla uproszczenia zakłada się, że bmp1 jest równa lub większa niż 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; 
} 

Dla bardziej złożonych algorytmów mieszających, może pomóc sobie z niektórymi dostępne funkcje Bitmap/Canvas.

+0

Dzięki, ale ta trasa i kolejna dyskusja doprowadziły mnie do przekonania, że ​​skomplikowane mieszanie nie jest możliwe za pośrednictwem płótna. Spowodowało to próbę miksowania na piksel. – MarkPowell