2012-01-06 13 views
6

Estoy escribiendo un generador fractal Buddhabrot usando aparapi. Obtuve la parte de OpenCL para que funcione, lo que resulta en una matriz de una sola dimensión que representa cada píxel. Tengo las dimensiones de la imagen final como entradas finales y he escrito un código para obtener el índice de puntos arbitrarios en esa matriz. Quiero guardar esto como una imagen y estoy tratando de usar BufferedImage con TYPE_USHORT_GRAY. Esto es lo que tengo hasta ahora:Convertir corto [] en una imagen en escala de grises

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

El problema es que no sé qué para ajustar el RGB como. ¿Que necesito hacer?

Respuesta

7

El problema aquí es que setRGB() quiere un valor de color 0xRRGGBB. A BufferedImage le gusta simular que la imagen es RGB, sin importar cómo se almacenan los datos. De hecho, puede obtener el DataBufferShort interno (con getTile(0, 0).getDataBuffer()), pero puede ser difícil averiguar cómo se presenta.

Si ya tiene sus píxeles en una short[], una solución más simple podría ser para copiarlos en un int[] lugar un atasco en una 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)); 

La ventaja de este enfoque es que permite controlar la matriz de píxeles subyacente. Podría hacer cambios en esa matriz y llamar al newPixels() en su MemoryImageSource, y se actualizaría en vivo. También le da el poder total para definir su propia paleta aparte de escala de grises:

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

Este enfoque funciona bien si sólo desea visualizar la imagen en la pantalla:

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

Sin embargo, si desea para escribirlo en un archivo y conservar el formato de uno-corto por píxel (por ejemplo, para cargarlo en Matlab), entonces no tiene suerte. Lo mejor que puede hacer es pintarlo en un BufferedImage y guardarlo con ImageIO, que se guardará como RGB.

Si definitivamente necesita un BufferedImage al final, otro enfoque es aplicar el color paleta de sí mismo, el cálculo de los valores RGB, y luego copiarlos en la imagen:

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

lo hacía, se dio cuenta de mi código de dibujo es FUBAR con ArrayOutOfBounds excepciones en todas partes. Mirándolo, parece que funcionaría bien. Todo lo que necesito hacer es generarlo como .png, lo que he hecho (afortunadamente) con éxito. Marcaré esto como correcto porque parece que funcionaría bien. –

+0

Cuando esto pone los píxeles en la imagen, ¿los dibuja en líneas verticales que comienzan en la izquierda y van a la derecha o horizontal que comienzan en la parte superior y bajan? Debido a que mi código de trabajo parcial tiene la imagen girada 90 grados en el sentido de las agujas del reloj y no creo que sea culpa del dibujo. –

+0

¡No importa!Tuve que cambiar el 200 en la parte MemoryImageSource a HORIZONTAL_PIXELS. Funciona genial, gracias! –

3

Como referencia, este ejemplo muestra cómo dos tipos diferentes de BufferedImage interpretan los mismos datos de 16 bits. Puede pasar el mouse sobre las imágenes para ver los valores de píxel.

Adición: Para más detalles sobre la palabra interpretar, tenga en cuenta que setRGB() trata de encontrar el valor más próximo al valor especificado en el ColorModel dada.

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

Técnicamente hablando, estos no muestran los mismos datos de 16 bits: muestran los mismos valores RGB cuando se los coacciona en escala de grises de USHORT o en RGB. Esto se debe a que setRGB() realiza una conversión de color en la paleta de la imagen; no solo escribe un valor de píxel. Si escribió el valor de píxel, el de escala de grises sería blanco en la parte inferior. –

+0

+1. Ejemplos de trabajo + respuestas con imágenes son agradables – Robin

+0

@RussellZahniser es correcto; más arriba. – trashgod

Cuestiones relacionadas