2010-02-13 12 views
10

Ho alcuni problemi con le immagini in rotazione in Java utilizzando la classe AffineTransform.Problemi di rotazione del bufferImmagine

ho il seguente metodo per creare un (90 gradi) copia ruotata di un'immagine:

private BufferedImage createRotatedCopy(BufferedImage img, Rotation rotation) { 
    int w = img.getWidth(); 
    int h = img.getHeight(); 

    BufferedImage rot = new BufferedImage(h, w, BufferedImage.TYPE_INT_RGB); 

    double theta; 
    switch (rotation) { 
     case CLOCKWISE: 
      theta = Math.PI/2; 
      break; 
     case COUNTERCLOCKWISE: 
      theta = -Math.PI/2; 
      break; 
     default: 
      throw new AssertionError(); 
    } 

    AffineTransform xform = AffineTransform.getRotateInstance(theta, w/2, h/2); 
    Graphics2D g = (Graphics2D) rot.createGraphics(); 
    g.drawImage(img, xform, null); 
    g.dispose(); 

    return rot; 
} 

rotazione è una semplice enum con valori NESSUNO, senso orario e antiorario.

I sintomi di miei problemi sono visualizzate qui:

http://perp.se/so/rotate_problems.html

Così, la rotazione funziona bene, ma le immagini risultanti non sono ancorate alle coordinate corrette (o come si dovrebbe metterlo). E poiché non so davvero cosa diavolo sto facendo in primo luogo (la mia algebra lineare è debole), non so come risolverlo da solo.

Ho provato con qualche giochetto casuale con l'istanza AffineTransform, ma non mi ha aiutato (ovviamente). Ho provato googling (e cercando SO), ma tutti gli esempi che ho visto fondamentalmente usano lo stesso approccio che faccio ... che non funziona per me.

Complimenti per un consiglio.

+1

domanda equivalente per NET: http://stackoverflow.com/questions/2225363/c-rotate-bitmap-90-degrees – finnw

risposta

16

Se si deve esprimere la trasformazione come un singolo di rotazione, il punto di ancoraggio dipende dalla direzione di rotazione: o (w/2, w/2) o (h/2, h/2).

Ma è probabilmente più semplice esprimere come translate; rotate; translate, ad es.

AffineTransform xform = new AffineTransform(); 
xform.translate(0.5*h, 0.5*w); 
xform.rotate(theta); 
xform.translate(-0.5*w, -0.5*h); 

Considera anche utilizzando getQuadrantRotateInstance invece di getRotateInstance.

+0

Ho capito quello che stai dicendo, e ho provato anche quello. Il problema persiste, tuttavia.Sono ancora disegnati "fuori" dall'area bersaglio, anche se "dall'altra parte" in senso orizzontale, per così dire. Potrei fornire altri screenshot se non è chiaro cosa sto ottenendo. – perp

+0

@perp, hai ragione, risolto. Ho provato la nuova versione e funziona. – finnw

+0

Funziona come un fascino! Penso di avere una migliore comprensione di quello che sta succedendo adesso. Grazie! – perp

0

Non so se questo potrebbe essere il tuo problema.

AffineTransform xform = AffineTransform.getRotateInstance(theta, w/2, h/2); 

Perché non provare?

AffineTransform xform = AffineTransform.getRotateInstance(theta); 

O

g.transform(AffineTransform.getRotateInstance(theta)); 
g.drawImage(img, 0, 0, w/2, h/2, null, null); 
+0

ho provato. :-) – perp

1

È possibile provare un appoach alternativo e creare un'icona dall'immagine e quindi utilizzare uno Rotated Icon.

Oppure si può provare questo vecchio codice che ho trovato nel forum di Sun:

import java.awt.*; 
import java.awt.geom.*; 
import java.awt.image.*; 
import java.io.*; 
import java.net.*; 
import javax.imageio.*; 
import javax.swing.*; 

public class RotateImage { 
    public static void main(String[] args) throws IOException { 
     URL url = new URL("https://blogs.oracle.com/jag/resource/JagHeadshot-small.jpg"); 
     BufferedImage original = ImageIO.read(url); 
     GraphicsConfiguration gc = getDefaultConfiguration(); 
     BufferedImage rotated1 = tilt(original, -Math.PI/2, gc); 
     BufferedImage rotated2 = tilt(original, +Math.PI/4, gc); 
     BufferedImage rotated3 = tilt(original, Math.PI, gc); 
     display(original, rotated1, rotated2, rotated3); 
    } 

    public static BufferedImage tilt(BufferedImage image, double angle, GraphicsConfiguration gc) { 
     double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle)); 
     int w = image.getWidth(), h = image.getHeight(); 
     int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin); 
     int transparency = image.getColorModel().getTransparency(); 
     BufferedImage result = gc.createCompatibleImage(neww, newh, transparency); 
     Graphics2D g = result.createGraphics(); 
     g.translate((neww-w)/2, (newh-h)/2); 
     g.rotate(angle, w/2, h/2); 
     g.drawRenderedImage(image, null); 
     return result; 
    } 

    public static GraphicsConfiguration getDefaultConfiguration() { 
     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     GraphicsDevice gd = ge.getDefaultScreenDevice(); 
     return gd.getDefaultConfiguration(); 
    } 

    public static void display(BufferedImage im1, BufferedImage im2, BufferedImage im3, BufferedImage im4) { 
     JPanel cp = new JPanel(new GridLayout(2,2)); 
     addImage(cp, im1, "original"); 
     addImage(cp, im2, "rotate -PI/2"); 
     addImage(cp, im3, "rotate +PI/4"); 
     addImage(cp, im4, "rotate PI"); 

     JFrame f = new JFrame("RotateImage"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setContentPane(cp); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    static void addImage(Container cp, BufferedImage im, String title) { 
     JLabel lbl = new JLabel(new ImageIcon(im)); 
     lbl.setBorder(BorderFactory.createTitledBorder(title)); 
     cp.add(lbl); 
    } 
} 
3

Dal momento che avete solo bisogno di 90 gradi di rotazione si può evitare di utilizzare la roba AffineTransform:

public BufferedImage rotate90DX(BufferedImage bi) { 
    int width = bi.getWidth(); 
    int height = bi.getHeight(); 
    BufferedImage biFlip = new BufferedImage(height, width, bi.getType()); 
    for(int i=0; i<width; i++) 
     for(int j=0; j<height; j++) 
      biFlip.setRGB(height-1-j, width-1-i, bi.getRGB(i, j)); 
    return biFlip; 
} 

Questo evita anche tagliare i bordi delle immagini rettangolari.

Da: http://snippets.dzone.com/posts/show/2936

+3

Solo un avviso, forzando un accesso diretto ai valori dei pixel RGB porta l'immagine fuori dalla pipeline accelerata in Java2D. Questo approccio può darti il ​​risultato che desideri, ma è molto più lento. –

+0

Aha. Non lo sapevo. Grazie –

+0

Ho testato questo codice e non ruota semplicemente l'immagine, ma cambia anche a destra ea sinistra (come in uno specchio) – Radon8472

Problemi correlati