Girare una matrice di pixel in un’Immagine a oggetti con Java ImageIO?

Attualmente sto girando un array di valori di pixel (originariamente creato con java.awt.immagine.PixelGrabber oggetto) in un oggetto Immagine utilizzando il seguente codice:

public Image getImageFromArray(int[] pixels, int width, int height) {
    MemoryImageSource mis = new MemoryImageSource(width, height, pixels, 0, width);
    Toolkit tk = Toolkit.getDefaultToolkit();
    return tk.createImage(mis);
}

È possibile ottenere lo stesso risultato utilizzando le classi di ImageIO pacchetto(s) così non devo usare il AWT Toolkit?

Toolkit.getDefaultToolkit() non sembra essere affidabile al 100% e a volte gettare un AWTError, mentre il ImageIO classi deve essere sempre disponibile, che è il motivo per cui io sono interessato a cambiare il mio metodo.



6 Replies
  1. 27

    È possibile creare l’immagine senza l’utilizzo di ImageIO. Basta creare un BufferedImage utilizzando un tipo di immagine, la corrispondenza del contenuto della matrice di pixel.

    public static Image getImageFromArray(int[] pixels, int width, int height) {
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                WritableRaster raster = (WritableRaster) image.getData();
                raster.setPixels(0,0,width,height,pixels);
                return image;
            }

    Quando si lavora con il PixelGrabber, non dimenticate di estrarre il RGBA info dalla matrice di pixel prima di chiamare getImageFromArray. C’è un esempio di questo nel handlepixelmethod in PixelGrabber javadoc. Una volta fatto questo, assicurarsi che il tipo di immagine in BufferedImage costruttore per BufferedImage.TYPE_INT_ARGB.

    • Grazie bcash, ma ho un java.lang.ArrayIndexOutOfBoundsException quando cerco di tale codice. Tutte le idee?
    • Penso che questo è vicino, ci potrebbero essere necessarie ulteriori dettagli da Chris con dettagli? questo appare come dovrebbe funzionare… Quali sono i vostri interi? sono RGB? ARGB? un qualche tipo di formato compresso?
    • I pixel sono provenienti da un PixelGrabber come ad esempio: int[] pixel = new int[larghezza * altezza]; PixelGrabber pg = new PixelGrabber(img, 0, 0, larghezza, l’altezza, in pixel, 0, larghezza); pg.grabPixels();
    • Chris, sei sempre un AOOB eccezione, perché la dimensione del BufferedImage “immagine” è la larghezza * altezza * 3, perché è di tipo int RGB. Vedere la modifica.
    • Quando ho provato questo codice, ho ottenuto un’immagine nera. E ‘ come il raster.setPixels non influenzano la BufferedImage a tutti.
    • Come @haraldK (qui sotto il post), ha notificato, la documentazione Java menziona che BufferedImage.getData() restituisce un Raster e BufferedImage.getRaster() restituisce un WritableRaster. Quindi, se si utilizza getData() sembra che restituisce una copia e dopo setPixels() si deve mettere indietro utilizzando BufferedImage.setData() che è un overhead. Quindi è meglio utilizzare getRaster() e lavorare con esso.

  2. 7

    Utilizzando il raster ho avuto un ArrayIndexOutOfBoundsException anche quando ho creato il BufferedImage con TYPE_INT_ARGB. Tuttavia, utilizzando il setRGB(...) metodo di BufferedImage ha funzionato per me.

    • Ho avuto un problema simile, anche se la dimensione del vettore di input e di output corrispondente. Ho finito per usare setRGB troppo. Potrebbe essere banalmente più lento ma funziona. Il non pensare Alpha vs non-alfa dovrebbe cambiare la dimensione della matrice, però da quando è semplicemente il 2 byte più significativi sui singoli int.
  3. 3

    JavaDoc su BufferedImage.getData() dice: “un Raster che è un copia dei dati dell’immagine.”

    Questo codice funziona per me, ma ho il dubbio nella sua efficienza:

            //Получаем картинку из массива.
            int[] pixels = new int[width*height];
                //Рисуем диагональ.
                for (int j = 0; j < height; j++) {
                    for (int i = 0; i < width; i++) {
                        if (i == j) {
                            pixels[j*width + i] = Color.RED.getRGB();
                        }
                        else {
                            pixels[j*width + i] = Color.BLUE.getRGB();
                            //pixels[j*width + i] = 0x00000000;
                        }
                    }
                }
    
    BufferedImage pixelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);    
        pixelImage.setRGB(0, 0, width, height, pixels, 0, width);
    • ..o utilizzare getRaster() invece di getData().
  4. 2

    Ho avuto un buon successo con java.awt.Robot per afferrare una schermata (o di un segmento dello schermo), ma per lavorare con ImageIO, è necessario memorizzare in un BufferedImage invece dell’immagine di memoria di origine. Quindi è possibile chiamare un metodo statico di ImageIO e salvare il file. Provare qualcosa di simile:

    //Capture whole screen
    Rectangle region = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    BufferedImage capturedImage = new Robot().createScreenCapture(region);
    
    //Save as PNG
    File imageFile = new File("capturedImage.png");
    ImageIO.write(capturedImage, "png", imageFile);
  5. 0

    Come questo è uno dei più votato domanda taggati con ImageIO COSÌ, penso che ci sia ancora spazio per una soluzione migliore, anche se la questione è vecchia. 🙂

    Guardare il BufferedImageFactory.java classe dal mio open source imageio progetto su GitHub.

    Con esso, si può semplicemente scrivere:

    BufferedImage image = new BufferedImageFactory(image).getBufferedImage();

    L’altra cosa buona è che questo approccio, come caso peggiore, ha circa le stesse prestazioni (tempo) come PixelGrabbera base di esempi già in questo thread. Per i casi più comuni (in genere JPEG), che è circa due volte più veloce. In ogni caso, si utilizza meno memoria.

    Come un bonus laterali, il modello di colore e layout di pixel dell’immagine originale viene mantenuto, invece di tradurre int ARGB con il colore di default del modello. Questo potrebbe salvare la memoria aggiuntiva.

    (PS: La fabbrica supporta anche il subsampling regione di interesse e di progresso ascoltatori se qualcuno è interessato. 🙂

  6. -1

    Ho avuto lo stesso problema di tutti gli altri, cercando di applicare la risposta corretta a questa domanda, il mio int array avere effettivamente un OutOfboundException dove ho risolto aggiungendo ancora una indice perché la lunghezza dell’array deve essere di larghezza*altezza*3 dopo questo non ho potuto ottenere l’immagine così ho risolto impostando il raster l’immagine

    public static Image getImageFromArray(int[] pixels, int width, int height) {
            BufferedImage image = new BufferedImage(width, height,     BufferedImage.TYPE_INT_ARGB);
            WritableRaster raster = (WritableRaster) image.getData();
            raster.setPixels(0,0,width,height,pixels);
            image.setData(raster); 
            return image;
        }

    E si può vedere l’immagine, se u si visualizza su un etichetta su un jframe come questo

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

    impostazione immagine imageIcon().
    Ultimo consiglio che si può provare a cambiare il Bufferedimage.TYPE_INT_ARGB per qualcosa d’altro, che corrisponde all’immagine che si ha la matrice di questo tipo è molto importante, ho avuto una matrice di 0 e -1, quindi ho usato questo tipo di BufferedImage.TYPE_3BYTE_BGR

Lascia un commento