【问题标题】:AffineTransform truncates image, what do I wrong?AffineTransform 截断图像,我做错了什么?
【发布时间】:2012-02-01 22:02:00
【问题描述】:

我这里有一个尺寸为 2156x1728 的黑白 png 文件,我想使用 AffineTransform 将其旋转 90 度。生成的图像没有正确的比例。这里有一些示例代码(假设我已成功将 png 文件加载到 BufferedImage 中):

public BufferedImage transform(BufferedImage image){

    System.out.println("Input width: "+ image.getWidth());
    System.out.println("Input height: "+ image.getHeight());

    AffineTransform affineTransform = new AffineTransform();
    affineTransform.setToQuadrantRotation(1, image.getWidth() / 2, image.getHeight() / 2);

    AffineTransformOp opRotated = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
    BufferedImage transformedImage = opRotated.createCompatibleDestImage(image, image.getColorModel());
    System.out.println("Resulting width: "+ transformedImage.getWidth());
    System.out.println("Resulting height: "+ transformedImage.getHeight());

    transformedImage = opRotated.filter(image, transformedImage);
    return transformedImage;
}

相应的输出是:

输入宽度:2156

输入高度:1728

结果宽度:1942

结果高度:1942

为什么旋转会返回如此完全不相关的维度?

【问题讨论】:

    标签: java awt affinetransform


    【解决方案1】:

    我不是这方面的专家,但为什么不直接创建一个正确大小的 BufferedImage 呢?另请注意,您的旋转中心不正确。您需要在 [w/2, w/2] 或 [h/2, h/2] 的中心上旋转(w 是宽度,h 是高度),具体取决于您要旋转到的象限,1 或 3 ,以及图像的相对高度和宽度。例如:

    import java.awt.geom.AffineTransform;
    import java.awt.image.AffineTransformOp;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    
    public class RotateImage {
       public static final String IMAGE_PATH = "http://duke.kenai.com/"
             + "models/Duke3DprogressionSmall.jpg";
    
       public static void main(String[] args) {
          try {
             URL imageUrl = new URL(IMAGE_PATH);
             BufferedImage img0 = ImageIO.read(imageUrl);
             ImageIcon icon0 = new ImageIcon(img0);
    
             int numquadrants = 1;
             BufferedImage img1 = transform(img0, numquadrants );
             ImageIcon icon1 = new ImageIcon(img1);
    
             JOptionPane.showMessageDialog(null, new JLabel(icon0));
             JOptionPane.showMessageDialog(null, new JLabel(icon1));
    
          } catch (MalformedURLException e) {
             e.printStackTrace();
          } catch (IOException e) {
             e.printStackTrace();
          }
       }
    
       public static BufferedImage transform(BufferedImage image, int numquadrants) {
          int w0 = image.getWidth();
          int h0 = image.getHeight();
          int w1 = w0;
          int h1 = h0;
    
          int centerX = w0 / 2;
          int centerY = h0 / 2;
    
          if (numquadrants % 2 == 1) {
             w1 = h0;
             h1 = w0;
          }
    
          if (numquadrants % 4 == 1) {
             if (w0 > h0) {
                centerX = h0 / 2;
                centerY = h0 / 2;
             } else if (h0 > w0) {
                centerX = w0 / 2;
                centerY = w0 / 2;
             }
             // if h0 == w0, then use default
          } else if (numquadrants % 4 == 3) {
             if (w0 > h0) {
                centerX = w0 / 2;
                centerY = w0 / 2;
             } else if (h0 > w0) {
                centerX = h0 / 2;
                centerY = h0 / 2;
             }
             // if h0 == w0, then use default
          }
    
          AffineTransform affineTransform = new AffineTransform();
          affineTransform.setToQuadrantRotation(numquadrants, centerX, centerY);
    
          AffineTransformOp opRotated = new AffineTransformOp(affineTransform,
                AffineTransformOp.TYPE_BILINEAR);
    
          BufferedImage transformedImage = new BufferedImage(w1, h1,
                image.getType());
    
          transformedImage = opRotated.filter(image, transformedImage);
          return transformedImage;
       }
    }
    

    编辑 1
    你问:

    你能解释一下为什么它必须是 [w/2, w/2] 或 [h/2, h/2] 吗?

    为了更好地解释这一点,最好可视化和物理操作一个矩形:

    剪下一张长方形的纸,把它放在一张纸上,使其左上角在纸的左上角——这就是你在屏幕上的图像。现在检查您需要将该矩形旋转 1 或 3 个象限的位置,使其新的左上角覆盖纸的左上角,您会明白为什么需要使用 [w/2, w/2] 或[h/2, h/2]。

    【讨论】:

    • 好的,我试试,你能解释一下为什么它必须是 [w/2, w/2] 或 [h/2, h/2] 吗?
    • 我发现您的解决方案可行,但需要稍作修正:定义 centerX、centerY 变量的代码需要切换大于/小于运算符。
    【解决方案2】:

    上述解决方案在图像的宽度和高度方面存在问题 下面的代码独立于 w > h || h > w

    public static BufferedImage rotateImage(BufferedImage image, int quadrants) {
    
        int w0 = image.getWidth();
        int h0 = image.getHeight();
        int w1 = w0;
        int h1 = h0;
        int centerX = w0 / 2;
        int centerY = h0 / 2;
    
        if (quadrants % 2 == 1) {
            w1 = h0;
            h1 = w0;
        }
    
        if (quadrants % 4 == 1) {
            centerX = h0 / 2;
            centerY = h0 / 2;
        } else if (quadrants % 4 == 3) {
            centerX = w0 / 2;
            centerY = w0 / 2;
        }
    
        AffineTransform affineTransform = new AffineTransform();
        affineTransform.setToQuadrantRotation(quadrants, centerX, centerY);
        AffineTransformOp opRotated = new AffineTransformOp(affineTransform,
                AffineTransformOp.TYPE_BILINEAR);
        BufferedImage transformedImage = new BufferedImage(w1, h1,
                image.getType());
        transformedImage = opRotated.filter(image, transformedImage);
    
        return transformedImage;
    
    }
    

    【讨论】:

      【解决方案3】:

      furykid's 回答很好,对我帮助很大。但它并不是那么完美。如果图像是矩形,则生成的旋转图像可能在一侧包含一些额外的黑色像素。

      我尝试了一张 Marty Feldman 的照片,可以在此链接中查看原始照片和结果: Marty Feldman rotation tests

      在黑色背景上很难看到,但在任何图像编辑软件上都可以轻松看到生成图像右侧和底部的黑色小边框。这对某些人来说可能不是问题,但如果它适合您,这里是固定代码(我将原始代码保留为注释以便于比较):

      public BufferedImage rotateImage(BufferedImage image, int quadrants) {
      
          int w0 = image.getWidth();
          int h0 = image.getHeight();
          /* These are not necessary anymore
          * int w1 = w0;
          * int h1 = h0;
          */
          int centerX = w0 / 2;
          int centerY = h0 / 2;
      
          /* This is not necessary anymore
          * if (quadrants % 2 == 1) {
          *     w1 = h0;
          *     h1 = w0;
          * }
          */
      
          //System.out.println("Original dimensions: "+w0+", "+h0);
          //System.out.println("Rotated dimensions: "+w1+", "+h1);
      
          if (quadrants % 4 == 1) {
              centerX = h0 / 2;
              centerY = h0 / 2;
          } else if (quadrants % 4 == 3) {
              centerX = w0 / 2;
              centerY = w0 / 2;
          }
      
          //System.out.println("CenterX: "+centerX);
          //System.out.println("CenterY: "+centerY);
      
          AffineTransform affineTransform = new AffineTransform();
          affineTransform.setToQuadrantRotation(quadrants, centerX, centerY);
          AffineTransformOp opRotated = new AffineTransformOp(affineTransform,
                  AffineTransformOp.TYPE_BILINEAR);
      
          /*Old code for comparison
          //BufferedImage transformedImage = new BufferedImage(w1, h1,image.getType());
          //transformedImage = opRotated.filter(image, transformedImage);
          */
          BufferedImage transformedImage = opRotated.filter(image, null);
          return transformedImage;
      
      }
      

      警告:前方有意见。我不确定发生这种情况的原因,但我有一个猜测。 如果你能更好地解释,请编辑。

      我相信这个“​​故障”的原因是奇怪的尺寸。 在计算新BufferedImage 的尺寸时,273 的高度将生成 136 的 centerY,例如,当正确值为 136.5 时。 这可能会导致旋转发生在稍微偏离中心的位置。但是,通过将null 发送到filter 作为目标图像,“BufferedImage 是使用源ColorModel 创建的”,这似乎效果最好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-21
        • 2012-07-19
        • 2011-06-22
        • 1970-01-01
        • 2011-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多