有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何确定和自动旋转图像?

我有很多图像,其中一些图像需要旋转

样本:

enter image description here

我想逆时针旋转这个图像90°

我在谷歌上搜索,想知道如何旋转图像,并找到了许多链接和线程。但是如何确定图像是否需要旋转呢?Picasa具有自动旋转功能。我想有类似的功能

任何指针都会对我很有帮助

我发现了一个link,但它与Android有关


共 (3) 个答案

  1. # 1 楼答案

    Roger Rowland提供的metadata-extractor指针解决了这个问题。我把它贴在这里以备将来参考:

    import java.awt.geom.AffineTransform;
    import java.awt.image.AffineTransformOp;
    import java.awt.image.BufferedImage;
    import java.io.File;
    
    import javax.imageio.ImageIO;
    
    import com.drew.imaging.ImageMetadataReader;
    import com.drew.metadata.Metadata;
    import com.drew.metadata.exif.ExifIFD0Directory;
    import com.drew.metadata.jpeg.JpegDirectory;
    
    public class Main {
    
        private static String inFilePath = "C:\\Users\\TapasB\\Desktop\\MHIS031522.jpg";
        private static String outFilePath = "C:\\Users\\TapasB\\Desktop\\MHIS031522-rotated.jpg";
    
        public static void main(String[] args) throws Exception {
            File imageFile = new File(inFilePath);
            BufferedImage originalImage = ImageIO.read(imageFile);
    
            Metadata metadata = ImageMetadataReader.readMetadata(imageFile);
            ExifIFD0Directory exifIFD0Directory = metadata.getDirectory(ExifIFD0Directory.class);
            JpegDirectory jpegDirectory = (JpegDirectory) metadata.getDirectory(JpegDirectory.class);
    
            int orientation = 1;
            try {
                orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
    
            int width = jpegDirectory.getImageWidth();
            int height = jpegDirectory.getImageHeight();
    
            AffineTransform affineTransform = new AffineTransform();
    
            switch (orientation) {
            case 1:
                break;
            case 2: // Flip X
                affineTransform.scale(-1.0, 1.0);
                affineTransform.translate(-width, 0);
                break;
            case 3: // PI rotation
                affineTransform.translate(width, height);
                affineTransform.rotate(Math.PI);
                break;
            case 4: // Flip Y
                affineTransform.scale(1.0, -1.0);
                affineTransform.translate(0, -height);
                break;
            case 5: // - PI/2 and Flip X
                affineTransform.rotate(-Math.PI / 2);
                affineTransform.scale(-1.0, 1.0);
                break;
            case 6: // -PI/2 and -width
                affineTransform.translate(height, 0);
                affineTransform.rotate(Math.PI / 2);
                break;
            case 7: // PI/2 and Flip
                affineTransform.scale(-1.0, 1.0);
                affineTransform.translate(-height, 0);
                affineTransform.translate(0, width);
                affineTransform.rotate(3 * Math.PI / 2);
                break;
            case 8: // PI / 2
                affineTransform.translate(0, width);
                affineTransform.rotate(3 * Math.PI / 2);
                break;
            default:
                break;
            }       
    
            AffineTransformOp affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);  
            BufferedImage destinationImage = new BufferedImage(originalImage.getHeight(), originalImage.getWidth(), originalImage.getType());
            destinationImage = affineTransformOp.filter(originalImage, destinationImage);
            ImageIO.write(destinationImage, "jpg", new File(outFilePath));
        }
    }
    
  2. # 2 楼答案

    有时,您无法使用相机拍摄的图像,也无法使用EXIF数据。在我的例子中,我有一个项目要扫描并导入数万张老式明信片到我们的数字存储库中,其中大部分是正面的风景,只有一小部分是肖像(即使在这些明信片上,背面仍然是风景)。为了尽可能减少扫描、桌面扫描和裁剪所需的时间,每次扫描和横向扫描(总是)要进行三次

    我来问这个问题,是想找到一个答案来自动检测和旋转这些纵向定向卡扫描

    关于基于摄像头元数据执行此操作,有很多讨论。有一些例子说明了如何使用机器学习自动调平相机未固定在地面/地平线上的照片。我还没有找到任何对我的情况有帮助的方法(这并不是说没有,但如果有,由于其他情况,很难找到)

    编辑2019年3月22日:这里有一个https://d4nst.github.io/2017/01/12/image-orientation/

    。。。,所以我确实想出了一个我要尝试的答案:

    对于每张卡的正面(使用ImageMagick和简单脚本进行批处理):

    1. 制作一个较小的jpeg版本的图像(因为我们不想使用200MB的图像)
    2. 再复制三份较小的jpeg,每一份都附加90度的旋转
    3. 将这四个方向中的每一个都提交到云机器学习API(我过去在Microsoft's方面很幸运)
    4. 分析答案。选择最详细和/或最自信的方向作为正确的方向
    5. 将原始全尺寸扫描旋转适当的量,并删除四个较小的JPEG

    我用一次扫描测试了这一点,在我的n=1的情况下,API有一个更长的标签列表和一个更好(而且更长)的正确方向的建议标题

    潜在问题:

    1. 云服务提供商可能会停止使用API,或者开始收取超出我们承受能力的费用(当我使用一批此类卡编写元数据创建测试脚本时,使用级别仍处于免费类别)
    2. 我认为微软可能已经在为OCR目的旋转你发送的图像(捕捉任何方向的文字),如果他们开始将更通用的元数据AI应用于所有方向,那么这可能会停止工作(尽管人们希望他们会在响应中添加一个键,以获得最佳方向猜测)
    3. (在我的情况下)明信片上的文字往往与图片不符(摄影工作室名称等)。如果他们没有像我猜想的那样做上述工作,那么在一次轮换中更好的OCR可能会欺骗脚本。如果OCR结果被证明是一个问题,人们可能不得不忽略它
    4. 使用带宽
  3. # 3 楼答案

    我在使用一些开关箱时遇到了一些问题。即使在没有旋转的情况下,仿射变换也会在图像中创建一个带有黑色空间的新图像,并会切掉一些维度。在这里,我使用元数据提取器类来确定应该是什么方向。然后我使用Imgscalr库进行缩放和旋转

    下面可以看到对我有效的完整解决方案。感谢Tapas Bose提供原始解决方案。我希望这对任何人都有帮助

    BufferedImage originalImage = Utils.prepareBufferedImage(fileUpload.getFile_data(), fileUpload.getFile_type());
                        BufferedImage scaledImg = Scalr.resize(originalImage, 200);
    
                        //    Begin orientation handling   
                        Metadata metadata = ImageMetadataReader.readMetadata(fileUpload.getFile_data());
                        ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
    
                        int orientation = Integer.parseInt(id);
                        try {
                            orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
                        } catch (Exception ex) {
                            logger.debug("No EXIF information found for image: " + fileUpload.getFile_name());
                        }
    
                        switch (orientation) {
                        case 1:
                            break;
                        case 2: // Flip X
                            scaledImg = Scalr.rotate(scaledImg, Rotation.FLIP_HORZ);
                            break;
                        case 3: // PI rotation
                            scaledImg = Scalr.rotate(scaledImg, Rotation.CW_180);
                            break;
                        case 4: // Flip Y
                            scaledImg = Scalr.rotate(scaledImg, Rotation.FLIP_VERT);
                            break;
                        case 5: // - PI/2 and Flip X
                            scaledImg = Scalr.rotate(scaledImg, Rotation.CW_90);
                            scaledImg = Scalr.rotate(scaledImg, Rotation.FLIP_HORZ);
                            break;
                        case 6: // -PI/2 and -width
                            scaledImg = Scalr.rotate(scaledImg, Rotation.CW_90);
                            break;
                        case 7: // PI/2 and Flip
                            scaledImg = Scalr.rotate(scaledImg, Rotation.CW_90);
                            scaledImg = Scalr.rotate(scaledImg, Rotation.FLIP_VERT);
                            break;
                        case 8: // PI / 2
                            scaledImg = Scalr.rotate(scaledImg, Rotation.CW_270);
                            break;
                        default:
                            break;
                        }       
                        //    End orientation handling   
    
                        if(fileUpload.getFile_type().toLowerCase().contains("jpeg")){
                            ImageIO.write(scaledImg, "jpeg", fileUpload.getFile_data());
                            user.setProfile_picture_ext("jpg");
                        }
                        else{
                            Sanselan.writeImage(scaledImg, fileUpload.getFile_data(), ImageFormat.IMAGE_FORMAT_PNG, null);
                            user.setProfile_picture_ext("png");
                        }