2010-02-13 42 views
10

Tôi có một số vấn đề với việc xoay hình ảnh trong Java bằng cách sử dụng lớp AffineTransform.Các sự cố khi xoay BufferedImage

tôi có phương pháp sau đây để tạo một xoay (90 độ) bản sao của một hình ảnh:

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

Rotation là một enum đơn giản với NONE giá trị, chiều kim đồng hồ và ngược chiều kim đồng.

Các triệu chứng của các vấn đề của tôi được hiển thị ở đây:

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

Vì vậy, luân chuyển hoạt động OK, nhưng những hình ảnh kết quả không được neo vào các tọa độ chính xác (hoặc làm thế nào ta nên đặt nó). Và kể từ khi tôi không thực sự biết những gì heck tôi đang làm ở nơi đầu tiên (đại số tuyến tính của tôi là yếu), tôi không biết làm thế nào để giải quyết điều này một mình.

Tôi đã thử với một số ngẫu nhiên không quan trọng với phiên bản AffineTransform, nhưng nó đã không giúp tôi (tất nhiên). Tôi đã thử googling (và tìm kiếm SO), nhưng tất cả các ví dụ tôi đã nhìn thấy về cơ bản sử dụng cách tiếp cận tương tự như tôi làm ... mà không làm việc cho tôi.

Cảm ơn lời khuyên.

+1

câu hỏi tương đương cho NET: http://stackoverflow.com/questions/2225363/c-rotate-bitmap-90-degrees – finnw

Trả lời

16

Nếu bạn phải thể hiện các biến đổi dưới dạng xoay vòng duy nhất, điểm neo phụ thuộc vào hướng quay: Hoặc (w/2, w/2) hoặc (h/2, h/2).

Nhưng có thể đơn giản hơn để biểu thị là translate; rotate; translate, ví dụ:

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

Đồng thời xem xét sử dụng getQuadrantRotateInstance thay vì getRotateInstance.

+0

Tôi nhận được những gì bạn đang nói, và tôi đã thử điều đó quá. Tuy nhiên, vấn đề vẫn tồn tại.Chúng vẫn đang được rút ra "bên ngoài" khu vực mục tiêu, mặc dù ở phía bên kia "" theo chiều ngang, do đó, để nói chuyện. Tôi có thể cung cấp thêm một số ảnh chụp màn hình nếu không rõ tôi đang nhận được gì. – perp

+0

@perp, bạn nói đúng, đã sửa. Tôi đã thử nghiệm phiên bản mới và nó hoạt động. – finnw

+0

Làm việc như một sự quyến rũ! Tôi nghĩ rằng tôi có một sự hiểu biết tốt hơn về những gì đang xảy ra bây giờ, quá. Cảm ơn! – perp

0

Tôi không biết đây có phải là vấn đề của bạn hay không.

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

Tại sao bạn không thử?

AffineTransform xform = AffineTransform.getRotateInstance(theta); 

HOẶC

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

Tôi đã thử nó. :-) – perp

1

Bạn có thể thử một appoach thay thế và tạo Biểu tượng từ hình ảnh và sau đó sử dụng Rotated Icon.

Hoặc bạn có thể thử mã này cũ tôi tìm thấy trong các diễn đàn 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

Vì bạn chỉ cần 90 xoay độ bạn có thể tránh sử dụng các công cụ 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; 
} 

này cũng tránh cắt các cạnh của hình ảnh hình chữ nhật.

Từ: http://snippets.dzone.com/posts/show/2936

+3

Chỉ cần một người đứng đầu, buộc một truy cập trực tiếp đến các giá trị pixel RGB lấy hình ảnh ra khỏi đường ống tăng tốc trong Java2D. Cách tiếp cận này có thể cung cấp cho bạn kết quả bạn muốn, nhưng nó chậm hơn nhiều. –

+0

Aha. Không biết điều đó. Cảm ơn –

+0

Tôi đã thử nghiệm mã này và nó không chỉ đơn giản là xoay hình ảnh, nó cũng thay đổi trái và phải (như trong gương) – Radon8472

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