【问题标题】:Blending pixels from Two Bitmaps混合来自两个位图的像素
【发布时间】:2011-01-05 14:44:39
【问题描述】:

我在这里撞墙了,我相当肯定我在做一些愚蠢的事情,所以是时候公开我的愚蠢了。

我正在尝试拍摄两张图像,然后使用标准混合算法(强光、柔光、叠加、乘法等)将它们混合成第三张图像。

因为 Android 没有内置这样的混合属性,所以我走上了获取每个像素并使用算法组合它们的路径。然而,结果是垃圾。下面是简单的多重混合的结果(使用的图像和预期结果)。

基地:

混合:

预期结果:

垃圾结果:

任何帮助将不胜感激。下面是代码,我试图去掉所有的“垃圾”,但有些可能已经通过了。如果有什么不清楚的地方我会清理它。

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

【问题讨论】:

    标签: android bitmap blending


    【解决方案1】:

    复制后,我认为您的问题与在 RGB565 模式下操作图像有关。正如this post 中所讨论的,位图显然需要处于 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.Modes。在我的快速(和肮脏)测试中,这是我能够让混合在非渐变图像上工作的唯一方法。

    【讨论】:

    • 凯文,感谢您的帮助。我不使用具有透明度的图像,因此不透明度始终为 1。我已经用图像更新了示例,并清理了代码。
    • 嗯,谢谢你的图片——这真的是一个垃圾结果。我目前无法访问 Android 开发环境,但我想知道它是否与位图的像素密度无关 - 看起来您的位图使用的是 RGB565 色彩空间,但它从文档看来,颜色在 ARGB4444 空间中工作。我还没有解析所有的位图/颜色文档以了解如何/是否自动处理此转换,但在我可以在实际平台上进行一些测试之前,可能值得一试。
    • 好吧,我玩了一下,我能够重现你的“垃圾”结果,我让它以两种不同的方式工作。我会尝试更改我原来的答案以反映这一点。
    • 非常感谢凯文,这真的让我明白了。关于 PorterDuff,我很乐意这样做。但是,我基本上需要复制一些 Photoshop 图层(Overlay、HardLight、SoftLight 等)。
    【解决方案2】:

    你可以这样做的简单叠加(为简单起见,假设 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; 
    } 
    

    对于更复杂的混合算法,也许您可​​以使用一些可用的位图/画布函数来帮助自己。

    【讨论】:

    • 谢谢,但它正在沿着这条路走下去,另一场讨论让我相信通过 Canvas 无法实现复杂的混合。这导致我尝试按像素混合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 2014-05-18
    相关资源
    最近更新 更多