2012-01-06 35 views
6

Tôi đang viết một máy phát điện fractab của Buddhabrot sử dụng aparapi. Tôi có một phần OpenCL của nó để làm việc, dẫn đến một mảng kích thước đơn đại diện cho mỗi điểm ảnh. Tôi có kích thước của hình ảnh cuối cùng như ints cuối cùng, và đã viết mã để có được chỉ số của các điểm tùy ý trong mảng đó. Tôi muốn lưu hình ảnh này dưới dạng hình ảnh và tôi đang cố gắng sử dụng BufferedImage với TYPE_USHORT_GRAY. Dưới đây là những gì tôi có cho đến thời điểm này:Chuyển đổi [] ngắn thành hình ảnh thang độ xám

BufferedImage image=new BufferedImage(VERTICAL_PIXELS, HORIZONTAL_PIXELS, BufferedImage.TYPE_USHORT_GRAY); 
    for(int i=0; i<VERTICAL_PIXELS; i++) 
     for(int k=0; k<HORIZONTAL_PIXELS; k++) 
      image.setRGB(k, i, normalized[getArrayIndex(k,i,HORIZONTAL_PIXELS)]); 

Vấn đề là, tôi không biết phải đặt RGB làm như thế nào. Tôi cần phải làm gì?

Trả lời

7

Vấn đề ở đây là setRGB() muốn có giá trị màu 0xRRGGBB. BufferedImage thích giả vờ rằng hình ảnh là RGB, bất kể dữ liệu được lưu trữ là gì. Bạn thực sự có thể nhận được tại các nội bộ DataBufferShort (với getTile(0, 0).getDataBuffer()), nhưng nó có thể được khôn lanh để tìm ra cách nó được đặt ra.

Nếu bạn đã có điểm ảnh của bạn trong một short[], một giải pháp đơn giản có thể là để sao chép chúng vào một int[] thay vì một mứt nó thành một MemoryImageSource:

int[] buffer = /* pixels */; 

ColorModel model = new ComponentColorModel(
    ColorSpace.getInstance(ColorSpace.CS_GRAY), new int[] { 16 }, 
    false, true, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); 

Image image = Toolkit.getDefaultToolkit().createImage(
    new MemoryImageSource(VERTICAL_PIXELS, HORIZONTAL_PIXELS, 
         model, buffer, 0, VERTICAL_PIXELS)); 

Ưu điểm của phương pháp này là bạn kiểm soát mảng pixel cơ bản. Bạn có thể thực hiện thay đổi đối với mảng đó và gọi newPixels() trên số MemoryImageSource của mình và sẽ cập nhật trực tiếp. Nó cũng cung cấp cho bạn sức mạnh hoàn toàn để xác định bảng màu của riêng bạn khác so với màu xám:

int[] cmap = new int[65536]; 
for(int i = 0; i < 65536; ++i) { 

    cmap[i] = (((i % 10000) * 256/10000) << 16) 
      | (((i % 20000) * 256/20000) << 8) 
      | (((i % 40000) * 256/40000) << 0); 
} 
ColorModel model = new IndexColorModel(16, 65536, cmap, 0, false, -1, DataBuffer.TYPE_USHORT); 

Cách tiếp cận này hoạt động tốt nếu bạn chỉ muốn hiển thị hình ảnh trên màn hình:

JFrame frame = new JFrame(); 
frame.getContentPane().add(new JLabel(new ImageIcon(image))); 
frame.pack(); 
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
frame.setVisible(true); 

Tuy nhiên, nếu bạn muốn để viết nó ra một tập tin và bảo toàn định dạng một-mỗi-pixel (nói, để tải vào Matlab) thì bạn sẽ không may mắn. Điều tốt nhất bạn có thể làm là vẽ nó vào một BufferedImage và lưu nó với ImageIO, sẽ lưu thành RGB.

Nếu bạn chắc chắn cần một BufferedImage ở cuối, cách tiếp cận khác là để áp dụng các màu palette mình, tính toán các giá trị RGB, và sau đó sao chép chúng vào hình ảnh:

short[] data = /* your data */; 
int[] cmap = /* as above */; 
int[] rgb = new int[data.length]; 

for(int i = i; i < rgb.length; ++i) { 
    rgb[i] = cmap[data[i]]; 
} 

BufferedImage image = new BufferedImage(
    VERTICAL_PIXELS, HORIZONTAL_PIXELS, 
    BufferedImage.TYPE_INT_RGB); 

image.setRGB(0, 0, VERTICAL_PIXELS, HORIZONTAL_PIXELS, 
    pixels, 0, VERTICAL_PIXELS); 
+0

tôi đã làm điều đó, sau đó nhận ra mã vẽ của tôi là FUBAR với ArrayOutOfBounds ngoại lệ ở khắp mọi nơi. Nhìn vào nó, mặc dù, nó có vẻ như nó sẽ làm việc tốt. Tất cả những gì tôi cần làm là xuất nó dưới dạng .png, mà tôi đã thực hiện (hy vọng) thành công. Tôi sẽ đánh dấu điều này là chính xác bởi vì nó có vẻ như nó sẽ làm việc tốt. –

+0

Khi điều này đặt các điểm ảnh trong hình ảnh, nó có vẽ chúng theo các đường thẳng đứng bắt đầu từ trái sang phải hoặc ngang mà bắt đầu ở trên cùng và đi xuống không? Vì mã làm việc một phần của tôi có hình ảnh xoay 90 độ theo chiều kim đồng hồ và tôi không nghĩ đó là lỗi của bản vẽ. –

+0

Nevermind!Tôi đã phải thay đổi 200 trong phần MemoryImageSource thành HORIZONTAL_PIXELS. Nó hoạt động tuyệt vời, cảm ơn! –

3

Để tham khảo, đây ví dụ chương trình làm thế nào hai loại khác nhau BufferedImage giải thích cùng một dữ liệu 16 bit. Bạn có thể di chuột qua các hình ảnh để xem các giá trị pixel.

Hợp đồng bổ sung: Để xây dựng trên từ giải thích, lưu ý rằng setRGB() cố gắng tìm giá trị gần nhất với giá trị được chỉ định trong ColorModel nhất định.

BufferedImageTest

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.image.BufferedImage; 
import java.util.Random; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

/** @see http://stackoverflow.com/questions/8765004 */ 
public class BufferedImageTest extends JPanel { 

    private static final int SIZE = 256; 
    private static final Random r = new Random(); 
    private final BufferedImage image; 

    public BufferedImageTest(int type) { 
     image = new BufferedImage(SIZE, SIZE, type); 
     this.setPreferredSize(new Dimension(SIZE, SIZE)); 
     for (int row = 0; row < SIZE; row++) { 
      for (int col = 0; col < SIZE; col++) { 
       image.setRGB(col, row, 0xff00 << 16 | row << 8 | col); 
      } 
     } 
     this.addMouseMotionListener(new MouseAdapter() { 

      @Override 
      public void mouseMoved(MouseEvent e) { 
       Point p = e.getPoint(); 
       int x = p.x * SIZE/getWidth(); 
       int y = p.y * SIZE/getHeight(); 
       int c = image.getRGB(x, y); 
       setToolTipText(x + "," + y + ": " 
        + String.format("%08X", c)); 
      } 
     }); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     g.drawImage(image, 0, 0, getWidth(), getHeight(), null); 
    } 

    static private void display() { 
     JFrame f = new JFrame("BufferedImageTest"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setLayout(new GridLayout(1, 0)); 
     f.add(new BufferedImageTest(BufferedImage.TYPE_INT_ARGB)); 
     f.add(new BufferedImageTest(BufferedImage.TYPE_USHORT_GRAY)); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       display(); 
      } 
     }); 
    } 
} 
+1

Về mặt kỹ thuật, chúng không hiển thị cùng một dữ liệu 16 bit - chúng hiển thị các giá trị RGB giống nhau khi được ép vào màu xám hoặc USHORT màu xám. Điều này là do setRGB() thực hiện chuyển đổi màu thành bảng màu của hình ảnh - nó không chỉ viết một giá trị pixel. Nếu nó đã viết giá trị pixel, màu xám sẽ có màu trắng ở phía dưới. –

+0

+1. Ví dụ làm việc + phản hồi với hình ảnh đẹp là – Robin

+0

@RussellZahniser là chính xác; ở trên. – trashgod

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