2012-01-05 34 views
10

Tôi có một phương thức chuyển đổi BufferedImages loại nào là TYPE_CUSTOM thành TYPE_INT_RGB. Tôi đang sử dụng các mã sau đây, tuy nhiên tôi thực sự muốn tìm một cách nhanh hơn để làm điều này.Thay thế nhanh hơn cho ColorConvertOp

BufferedImage newImg = new BufferedImage(
    src.getWidth(), 
    src.getHeight(), 
    BufferedImage.TYPE_INT_RGB); 

ColorConvertOp op = new ColorConvertOp(null); 
op.filter(src, newImg); 

Nó hoạt động tốt, tuy nhiên nó khá chậm và tôi tự hỏi nếu có một cách nhanh hơn để thực hiện chuyển đổi này.

ColorModel Trước khi chuyển đổi:

ColorModel: #pixelBits = 24 numComponents = 3 color space = [email protected] transparency = 1 has alpha = false isAlphaPre = false 

ColorModel Sau khi chuyển đổi:

DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 

Cảm ơn!


Cập nhật:

Hóa ra làm việc với các dữ liệu pixel nguyên bản là cách tốt nhất. Kể từ khi TYPE_CUSTOM thực sự RGB chuyển đổi nó bằng tay là đơn giản và nhanh hơn khoảng 95% so với ColorConvertOp.

public static BufferedImage makeCompatible(BufferedImage img) throws IOException { 
    // Allocate the new image 
    BufferedImage dstImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB); 

    // Check if the ColorSpace is RGB and the TransferType is BYTE. 
    // Otherwise this fast method does not work as expected 
    ColorModel cm = img.getColorModel(); 
    if (cm.getColorSpace().getType() == ColorSpace.TYPE_RGB && img.getRaster().getTransferType() == DataBuffer.TYPE_BYTE) { 
     //Allocate arrays 
     int len = img.getWidth()*img.getHeight(); 
     byte[] src = new byte[len*3]; 
     int[] dst = new int[len]; 

     // Read the src image data into the array 
     img.getRaster().getDataElements(0, 0, img.getWidth(), img.getHeight(), src); 

     // Convert to INT_RGB 
     int j = 0; 
     for (int i=0; i<len; i++) { 
      dst[i] = (((int)src[j++] & 0xFF) << 16) | 
        (((int)src[j++] & 0xFF) << 8) | 
        (((int)src[j++] & 0xFF)); 
     } 

     // Set the dst image data 
     dstImage.getRaster().setDataElements(0, 0, img.getWidth(), img.getHeight(), dst); 

     return dstImage; 
    } 

    ColorConvertOp op = new ColorConvertOp(null); 
    op.filter(img, dstImage); 

    return dstImage; 
} 

Trả lời

6

BufferedImages chậm một cách đau đớn. Tôi có một giải pháp nhưng tôi không chắc chắn bạn sẽ thích nó. Cách nhanh nhất để xử lý và chuyển đổi hình ảnh đệm là trích xuất mảng dữ liệu thô từ bên trong BufferedImage. Bạn làm điều đó bằng cách gọi buffImg.getRaster() và chuyển đổi nó thành raster cụ thể. Sau đó gọi raster.getDataStorage(). Một khi bạn có quyền truy cập vào dữ liệu thô, bạn có thể viết mã xử lý hình ảnh nhanh chóng mà không có tất cả sự trừu tượng trong BufferedImages làm chậm nó xuống. Kỹ thuật này cũng đòi hỏi một sự hiểu biết sâu sắc về các định dạng hình ảnh và một số kỹ thuật đảo ngược về phía bạn. Đây là cách duy nhất tôi có thể nhận được mã xử lý hình ảnh để chạy đủ nhanh cho các ứng dụng của tôi.

Ví dụ:

ByteInterleavedRaster srcRaster = (ByteInterleavedRaster)src.getRaster(); 
byte srcData[] = srcRaster.getDataStorage(); 

IntegerInterleavedRaster dstRaster = (IntegerInterleavedRaster)dst.getRaster(); 
int dstData[] = dstRaster.getDataStorage(); 

dstData[0] = srcData[0] << 16 | srcData[1] << 8 | srcData[2]; 

hoặc một cái gì đó như thế. Mong đợi lỗi trình biên dịch cảnh báo bạn không truy cập vào trình quản lý cấp thấp như vậy. Nơi duy nhất tôi có vấn đề với kỹ thuật này là bên trong các applet nơi một sự vi phạm truy cập sẽ xảy ra.

+0

Đẹp! Làm việc với dữ liệu thô cắt giảm thời gian xử lý 95% !! Xem bài đăng đã chỉnh sửa để biết chính xác cách tôi kết thúc việc này. –

+0

Tôi đã không kết thúc bằng cách sử dụng các lớp ByteInterleavedRaster và IntegerInterleavedRaster vì một số lý do tôi không có các gói mặt trời. –

+0

Holy crap Tôi vừa mới xử lý tệp 100MB + psd trong 10 phút đến 8 giây. Cảm ơn! – EdgeCaseBerg

0

Bạn đã thử cung cấp bất kỳ RenderingHints? Không đảm bảo, nhưng sử dụng

ColorConvertOp op = new ColorConvertOp(new RenderingHints(
    RenderingHints.KEY_COLOR_RENDERING, 
    RenderingHints.VALUE_COLOR_RENDER_SPEED)); 

thay vì null trong đoạn mã của bạn có thể tăng tốc độ phần nào.

+0

Cố gắng đó, không may mắn :( –

0

Tôi nghi ngờ vấn đề có thể là ColorConvertOp() hoạt động pixel-by-pixel (được bảo đảm là "chậm").

Q: Bạn có thể sử dụng gc.createCompatibleImage() không?

Q: Màu nền bitmap ban đầu của bạn có đúng hay không, hoặc sử dụng bản đồ màu?

Q: Không có gì khác, bạn có dễ chịu khi viết giao diện JNI không? Hoặc là mã C tùy chỉnh của riêng bạn hoặc vào thư viện bên ngoài chẳng hạn như ImageMagick?

+0

Ngoài ra - có bạn nhìn vào bất kỳ cuộc gọi ImageIO mới nào trong Java 6 ++? http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html – paulsm4

+0

gc.createCompatibleImage() sẽ không hoạt động (không có đầu máy), bitmap là màu đích thực, tôi không phản đối việc sử dụng JNI hoặc Ima geMagick đang chờ xử lý, tôi có thể nhận được kết quả tương tự như sử dụng ColorConvertOp. –

+0

Tôi đang sử dụng ImageIO với gia tốc gốc để mở JPG. –

0

Nếu bạn đã cài đặt JAI, bạn có thể thử gỡ cài đặt nó, nếu có thể, hoặc tìm cách tắt codecLib khi tải JPEG. Trong một kiếp trước tôi có những vấn đề tương tự (http://www.java.net/node/660804) và ColorConvertOp là nhanh nhất vào thời điểm đó.

Khi tôi nhớ lại vấn đề cơ bản là Java2D không được tối ưu hóa cho hình ảnh TYPE_CUSTOM nói chung. Khi bạn cài đặt JAI, nó đi kèm với codecLib có bộ giải mã trả về TYPE_CUSTOM và được sử dụng thay cho mặc định. Danh sách JAI có thể cung cấp thêm trợ giúp, đã được vài năm.

-1

có thể thử điều này:

Bitmap source = Bitmap.create(width, height, RGB_565);//don't remember exactly... 
Canvas c = new Canvas(source); 
// then 
c.draw(bitmap, 0, 0); 

Sau đó bitmap nguồn sẽ được sửa đổi.

Sau đó bạn có thể làm:

onDraw(Canvas canvas){ 
canvas.draw(source, rectSrs,rectDestination, op); 
} 

nếu bạn có thể quản lý luôn tái sử dụng bitmap, do đó bạn có thể có được hiệu suất tốt hơn.Bạn cũng có thể sử dụng các chức năng canvas khác để vẽ bitmap của mình

2

Tôi đã tìm thấy kết xuất bằng Graphics.drawImage() thay vì ColorConvertOp nhanh hơn 50 lần. Tôi chỉ có thể giả định rằng drawImage() là GPU tăng tốc.

tức này là rất chậm, giống như 50ms một đi cho 100x200 hình chữ nhật

public void BufferdImage convert(BufferedImage input) { 
    BufferedImage output= new BufferedImage(input.getWidht(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CUSTOM_PALETTE); 

    ColorConvertOp op = new ColorConvertOp(input.getColorModel().getColorSpace(), 
              output.getColorModel().getColorSpace()); 

    op.filter(input, output); 
    return output; 
} 

tức tuy nhiên điều này đăng ký < 1ms cho cùng một đầu vào

public void BufferdImage convert(BufferedImage input) { 
    BufferedImage output= new BufferedImage(input.getWidht(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CUSTOM_PALETTE); 

    Graphics graphics = output.getGraphics(); 
    graphics.drawImage(input, 0, 0, null); 
    graphics.dispose(); 
    return output; 
} 
Các vấn đề liên quan