2011-01-05 41 views
13

Tôi đang đập đầu vào một bức tường ở đây, và tôi khá chắc chắn tôi đang làm điều gì đó ngu ngốc, vì vậy thời gian để làm cho sự ngu xuẩn của tôi công khai.Điểm ảnh trộn từ hai ảnh bitmap

Tôi đang cố gắng chụp hai hình ảnh, trộn chúng lại với nhau thành hình ảnh thứ ba bằng cách sử dụng các thuật toán trộn chuẩn (Hardlight, softlight, overlay, multiply, vv).

Vì Android không có các thuộc tính pha trộn như vậy, tôi đã đi xuống đường dẫn lấy từng pixel và kết hợp chúng bằng thuật toán. Tuy nhiên, kết quả là rác. Dưới đây là kết quả của sự pha trộn nhân đơn giản (hình ảnh được sử dụng và kết quả mong đợi).

BASE: alt text

Blend: alt text

DỰ KIẾN KẾT QUẢ: alt text

RÁC KẾT QUẢ: alt text

Bất kỳ trợ giúp sẽ được đánh giá cao. Dưới đây là mã, mà tôi đã cố gắng để loại bỏ tất cả các "rác", nhưng một số có thể đã làm cho nó thông qua. Tôi sẽ làm sạch nó nếu một cái gì đó không rõ ràng.

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

Trả lời

13

Sau khi tái tạo, tôi cho rằng vấn đề của bạn phải thực hiện khi thao tác với hình ảnh ở chế độ RGB565. Như đã thảo luận trong this post, các bitmap dường như cần phải ở chế độ ARGB8888 để thao tác đúng cách. đầu tiên tôi nhận được kết quả mong đợi về một sự pha trộn nhân bằng cách làm như sau:

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

Chuyển đổi các file ảnh để ARGB8888 chế độ dường như làm việc cho tôi, ít nhất là với các mô hình thử nghiệm gradient. Tuy nhiên, nó, bạn chỉ cần làm Screen hoặc Multiply, bạn có thể thử này cũng như:

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

Với điều đó, bạn không làm các tính toán cho mỗi pixel, nhưng bạn được giới hạn cho các cài đặt trước PorterDuff.Mode s. Trong thử nghiệm nhanh chóng (và bẩn) của tôi, đây là cách duy nhất tôi có thể làm cho việc pha trộn hoạt động trên các hình ảnh không có độ dốc.

+0

Kevin, cảm ơn sự giúp đỡ. Tôi không sử dụng hình ảnh với độ trong suốt, vì vậy độ mờ sẽ luôn là 1. Tôi đã cập nhật ví dụ với hình ảnh và làm sạch mã. – MarkPowell

+0

Hmm cảm ơn các hình ảnh - đó thực sự là kết quả rác. Tôi không có quyền truy cập vào một môi trường Android dev vào lúc này, nhưng tôi tự hỏi nếu nó không có gì để làm với mật độ điểm ảnh của Bitmap - có vẻ như Bitmap của bạn đang sử dụng không gian màu RGB565, nhưng nó dường như từ các tài liệu mà Color hoạt động trong không gian ARGB4444. Tôi đã không phân tích cú pháp thông qua tất cả các tài liệu Bitmap/Color để xem cách/nếu chuyển đổi này được xử lý tự động, nhưng có thể đáng để kiểm tra cho đến khi tôi có thể thực hiện một số thử nghiệm trên nền tảng thực tế. –

+0

Được rồi, tôi đã chơi với nó một chút và tôi đã có thể tái tạo kết quả 'rác' của bạn, và tôi đã làm cho nó hoạt động theo hai cách khác nhau.Tôi sẽ cố gắng thay đổi câu trả lời ban đầu để phản ánh điều này. –

4

Simple overlay bạn có thể làm theo cách này (vì đơn giản nó được cho rằng bmp1 là bằng hoặc lớn hơn 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; 
} 

Đối với thuật toán trộn phức tạp hơn, có lẽ bạn có thể giúp mình với một số các chức năng Bitmap/Canvas có sẵn.

+0

Cảm ơn, nhưng nó đã đi xuống con đường đó và một cuộc thảo luận khác khiến tôi tin rằng việc pha trộn phức tạp là không thể thông qua Canvas. Điều này dẫn đến việc tôi cố gắng trộn từng pixel. – MarkPowell

Các vấn đề liên quan