【问题标题】:Rotating Image with AffineTransform Produces Visually Correct Pixels, but getRGB Doesn't Match使用 AffineTransform 旋转图像会产生视觉上正确的像素,但 getRGB 不匹配
【发布时间】:2020-08-07 22:47:14
【问题描述】:

我正在尝试使用 AffineTransform 将图像旋转 180 度。我的“out.jpg”在视觉上看起来是旋转的,但是当我尝试以编程方式验证输出图像是否已旋转时,代码不同意。这是我的代码:

public static void main(String[] args) throws Exception {
    BufferedImage origImage = ImageIO.read(new File("input.jpg"));
    
    AffineTransform af = new AffineTransform();
    int centerX = origImage.getWidth() / 2;
    int centerY = origImage.getHeight() / 2;
    // Rotate 180 degrees
    af.quadrantRotate(2, centerX, centerY);

    AffineTransformOp affineTransformOp = new AffineTransformOp(af, null);
    BufferedImage destImage =
        new BufferedImage(origImage.getWidth(), origImage.getHeight(), origImage.getType());
    affineTransformOp.filter(origImage, destImage);

    // Verify that destImage has indeed been rotated by point checking a random pixel.
    int origX = 90;
    int origY = 32;
    // Where we expect this pixel to have been translated to.
    int expX = destImage.getWidth()-origX;
    int expY = destImage.getHeight()-origY;

    // Always prints false. Why????
    System.out.println("Pixels are equal: " +
      origImage.getRGB(origX, origY) == destImage.getRGB(expX, expY));

    ImageIO.write(destImage, "jpg", new File("out.jpg"));

}

我的轮换或程序检查有什么问题?

我已在文档中验证:

  • getRGB() 返回一个int,不需要使用.equals()
  • BufferedImage 索引从左上角 (0,0) 开始
  • 带有锚点的 AffineTransform.quadrantRotate(),一旦完成旋转,就会转换回 (0,0)
  • AffineTransform.quadrantRotate() 顺时针旋转(尽管这对于 180 度旋转应该无关紧要)

感谢您的帮助!

【问题讨论】:

    标签: java image


    【解决方案1】:

    您正在查看错误的像素。

    假设您的图像大小为1x1 像素。您最初查看的是像素(0, 0)。然后使用您的代码,在目标图像中,您正在查看像素(width - 0, height - 1),结果是像素(1, 1)。显然,您仍然需要查看(0, 0),因为图像在(1, 1) 处没有像素。

    在您的情况下,您转换后的坐标不在图像之外,但它指向错误的像素。

    要修复您的代码,请更改计算 expXexpY 值的行,并从每个值中减去 1:

    int expX = destImage.getWidth() - origX - 1;
    int expY = destImage.getHeight() - origY - 1;
    

    当我运行你的代码时返回正确的像素值(在我自己的图像上,因为你没有提供你使用的图像)。

    代码中还有另一个问题,它只会以奇数的宽度或高度显示:您正在使用整数运算来确定旋转中心,当不应该时,它会向下取整。将确定中心的线更改为(使用浮点数,以便您可以得到一个小数作为结果):

    double centerX = origImage.getWidth() / 2.0;
    double centerY = origImage.getHeight() / 2.0;
    

    【讨论】:

    • 有两个相关问题,其中一个是一个错误,因此将此解决方案标记为答案。此外,我正在旋转 JPEG 图像,这是有损的,因此像素值并不完全相同。当我更新检查以查看红色、绿色、蓝色值是否为预期值的 +/- 5 时,我得到了预期结果。
    【解决方案2】:

    我使用我的 png 图像运行您的代码。这是我的测试结果。图像类型 6 是来自BufferedImage source code 的 TYPE_4BYTE_ABGR。

    Image size: 416 x 199
    Image type: 6
    Origin pixel: 90,32
    Destination pixel: 326,167
    Pixel values: ffeeeeee ffffffff
    Pixels are equal: false
    

    这是图片。

    这是旋转后的图像。

    我不确定为什么颜色不同。我无法直观地区分 eeeeee 像素和 ffffff 像素之间的区别。

    编辑添加:我做了更多研究,发现Image getRGB 方法的这一点文档。

    返回默认 RGB 颜色模型中的整数像素(TYPE_INT_ARGB) 和默认的 sRGB 颜色空间。如果这发生了颜色转换 默认模型与图像 ColorModel 不匹配。

    因此,getRGB 方法本身可能会导致颜色转换。

    这是我运行的代码。

    import java.awt.geom.AffineTransform;
    import java.awt.image.AffineTransformOp;
    import java.awt.image.BufferedImage;
    import java.io.File;
    
    import javax.imageio.ImageIO;
    
    public class RotateImage {
    
        public static void main(String[] args) throws Exception {
            String input = "C:\\Users\\Owner\\OneDrive\\Pictures"
                    + "\\Saved Pictures\\CustomJTextField.png";
            BufferedImage origImage = ImageIO.read(new File(input));
    
            AffineTransform af = new AffineTransform();
            int centerX = origImage.getWidth() / 2;
            int centerY = origImage.getHeight() / 2;
            // Rotate 180 degrees
            af.quadrantRotate(2, centerX, centerY);
    
            AffineTransformOp affineTransformOp = new AffineTransformOp(
                    af, null);
            System.out.println("Image size: " + origImage.getWidth() +
                    " x " + origImage.getHeight());
            System.out.println("Image type: " + origImage.getType());
            BufferedImage destImage = new BufferedImage(
                    origImage.getWidth(), origImage.getHeight(),
                    origImage.getType());
            affineTransformOp.filter(origImage, destImage);
    
            // Verify that destImage has indeed been rotated by point
            // checking a random
            // pixel.
            int origX = 90;
            int origY = 32;
            // Where we expect this pixel to have been translated to.
            int expX = destImage.getWidth() - origX;
            int expY = destImage.getHeight() - origY;
    
            System.out.println("Origin pixel: " + origX + "," + origY);
            System.out.println("Destination pixel: " + expX + "," + expY);
    
            int origPixel = origImage.getRGB(origX, origY);
            int expPixel = destImage.getRGB(expX, expY);
            System.out.println("Pixel values: " +
                    Integer.toHexString(origPixel) + " " +
                    Integer.toHexString(expPixel));
    
            // Always prints false. Why????
            System.out.println("Pixels are equal: " +
                    (origPixel == expPixel));
    
            String output = "C:\\Eclipse\\Eclipse-2020-workspace"
                    + "\\com.ggl.testing2\\resources\\output.png";
            ImageIO.write(destImage, "png", new File(output));
        }
    
    }
    

    编辑补充:我写了自己的变换,看看是变换改变颜色还是getRGB方法改变颜色。

    这是我自己转换的测试结果。

    Image size: 416 x 199
    Image type: 6
    Origin pixel: 90,32
    Destination pixel: 326,167
    Pixel values: ffeeeeee ffeeeeee
    Pixels are equal: true
    

    我从原始图像创建了一个 int 像素数组,并将这些像素写入旋转后的图像。

    这是代码。

    import java.awt.image.BufferedImage;
    import java.io.File;
    
    import javax.imageio.ImageIO;
    
    public class RotateImage {
    
        public static void main(String[] args) throws Exception {
            String input = "C:\\Users\\Owner\\OneDrive\\Pictures"
                    + "\\Saved Pictures\\CustomJTextField.png";
            BufferedImage origImage = ImageIO.read(new File(input));
    
            System.out.println("Image size: " + origImage.getWidth() +
                    " x " + origImage.getHeight());
            System.out.println("Image type: " + origImage.getType());
            int[] pixels = getPixels(origImage);
    
            BufferedImage destImage = new BufferedImage(
                    origImage.getWidth(), origImage.getHeight(),
                    origImage.getType());
            destImage = putPixels(destImage, pixels);
    
            // Verify that destImage has indeed been rotated by point
            // checking a random
            // pixel.
            int origX = 90;
            int origY = 32;
            // Where we expect this pixel to have been translated to.
            int expX = destImage.getWidth() - origX;
            int expY = destImage.getHeight() - origY;
    
            System.out.println("Origin pixel: " + origX + "," + origY);
            System.out.println("Destination pixel: " + expX + "," + expY);
    
            int origPixel = origImage.getRGB(origX, origY);
            int expPixel = destImage.getRGB(expX, expY);
            System.out.println("Pixel values: " +
                    Integer.toHexString(origPixel) + " " +
                    Integer.toHexString(expPixel));
            System.out.println("Pixels are equal: " +
                    (origPixel == expPixel));
    
            String output = "C:\\Eclipse\\Eclipse-2020-workspace"
                    + "\\com.ggl.testing2\\resources\\output.png";
            ImageIO.write(destImage, "png", new File(output));
        }
    
        private static int[] getPixels(BufferedImage image) {
            int length = image.getWidth() * image.getHeight();
            int[] pixels = new int[length];
            int index = 0;
    
            for (int h = 0; h < image.getHeight(); h++) {
                for (int w = 0; w < image.getWidth(); w++) {
                    pixels[index++] = image.getRGB(w, h);
                }
            }
    
            return pixels;
        }
    
        private static BufferedImage putPixels(BufferedImage image,
                int[] pixels) {
            int index = 0;
    
            for (int i = pixels.length - 1; i >= 0; i--) {
                int h = index / image.getWidth();
                int w = index % image.getWidth();
                image.setRGB(w, h, pixels[i]);
                index++;
            }
    
            return image;
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2013-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-29
      • 1970-01-01
      • 2020-12-31
      • 1970-01-01
      相关资源
      最近更新 更多