Как определить и автоматически повернуть изображения?

У меня есть куча изображений, среди них некоторые изображения нужно повернуть.

Образец:

введите здесь описание изображения

Я хочу повернуть это изображение на 90° против часовой стрелки.

Я погуглил, чтобы узнать, как повернуть изображение, и нашел много ссылок и тем ТАК. Но как я могу определить, нужно ли поворачивать изображение? В Picasa есть функция автоповорота. Я хочу иметь аналогичный функционал.

Любой указатель был бы очень полезен для меня.

Я нашел ссылку но это связано с андроидом.


person Tapas Bose    schedule 22.02.2014    source источник
comment
Очень сложно. Что, если она действительно лежала?   -  person Roger Rowland    schedule 22.02.2014
comment
@RogerRowland хорошо: D. Может быть, если можно определить, является ли изображение, которое должно быть портретным, но размещено как альбомное, тогда только мы можем его повернуть! Я не уверен, правильно ли я подумал.   -  person Tapas Bose    schedule 22.02.2014
comment
Может быть, некоторые форматы изображений имеют подсказку в метаданных? Кажется, я что-то припоминаю в EXIF ​​(мысли вслух)...   -  person Roger Rowland    schedule 22.02.2014
comment
@RogerRowland Я нашел эту ссылку stackoverflow.com/questions/12726860/, он имеет дело с EXIF, но речь идет об Android.   -  person Tapas Bose    schedule 22.02.2014
comment
Если вам нужен код Java, может быть, это будет полезно? Или, возможно, это?   -  person Roger Rowland    schedule 22.02.2014
comment
@RogerRowland большое спасибо. Ваш указатель решил проблему. Если вы предоставите указатель в качестве ответа на этот вопрос, я могу его принять.   -  person Tapas Bose    schedule 24.02.2014
comment
Нет проблем, вы уже опубликовали ответ, просто примите это - я не беспокоюсь о репутации, пока вы в порядке :-)   -  person Roger Rowland    schedule 24.02.2014
comment
Если изображение имеет тег ориентации EXIF, то использование ImageMagick автоматически переориентирует изображение. convert image -auto-orient result. см. imagemagick.org/script/command-line-options.php#auto -ориентация   -  person fmw42    schedule 08.11.2018
comment
Размещенное вами изображение не имеет данных EXIF. Но это может быть связано с процессом загрузки на этот форум. В Imagemagick с текущими версиями вы можете использовать convert image -format "%[EXIF:orientation]" info:, чтобы увидеть, есть ли такое на вашем изображении. В качестве альтернативы вы можете сделать identify -verbose image и просмотреть длинный список информации для тегов EXIF, если они существуют. Если изображение не имеет ориентации EXIF, ваша проблема становится намного сложнее. Вероятно, вам понадобится какой-то код для глубокого обучения, но я не видел ничего подобного, хотя и не искал такой.   -  person fmw42    schedule 08.11.2018
comment
Для решения Python см.: stackoverflow.com /вопросы/4228530/   -  person Alma Rahat    schedule 06.08.2020


Ответы (3)


Указатель извлекателя метаданных, который Roger Rowland решил проблему. Я размещаю его здесь для дальнейшего использования:

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));
    }
}
person Tapas Bose    schedule 24.02.2014
comment
Я думаю, что API изменился в текущей версии (2.8.1 на момент написания) экстрактора метаданных: metadata.getDirectory теперь metadata.getFirstDirectoryOfType. - person bballant; 04.02.2016

У меня были некоторые проблемы с работой некоторых переключателей. Даже если поворота не было, AffineTransform создавал новое изображение с черным пространством в изображении и обрезал некоторые измерения. Отказавшись от принятого здесь ответа, я использовал класс экстрактора метаданных, чтобы определить, какой должна быть ориентация. Затем я использовал библиотеку 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");
                    }
person rawkfist0215    schedule 09.06.2015

Иногда вы не работаете с изображениями, снятыми камерой, и у вас нет данных EXIF ​​для работы. В моем случае у меня есть проект по сканированию и импорту в наш цифровой репозиторий десятков тысяч старинных открыток, большинство из которых имеют альбомную ориентацию на лицевой стороне и лишь небольшой процент из них портретные (обратная сторона остается альбомной даже на этих). Чтобы свести к минимуму время, затрачиваемое на сканирование, устранение перекоса и обрезку, они выполняются по три на сканирование и в альбомной ориентации (всегда).

Я пришел к этому вопросу в поисках ответа на автоматизацию обнаружения и поворота этих сканов карт с портретной ориентацией.

Существует много дискуссий о том, как сделать это на основе метаданных камеры. Есть несколько примеров того, как использовать машинное обучение для автоматического выравнивания фотографии, на которой камера не была направлена ​​прямо к земле/горизонту. Я не нашел ничего, что помогло бы в моей ситуации (это не значит, что их нет, но если они есть, их трудно найти из-за других ситуаций)...

EDIT 22.03.2019: вот один из https://d4nst.github.io/2017/01/12/image-orientation/

..., поэтому я придумал ответ, который собираюсь попробовать:

Для каждой лицевой стороны карты (пакетная обработка с помощью ImageMagick и простых скриптов):

  1. Сделайте уменьшенную версию изображения в формате jpeg (потому что мы не хотим работать с изображениями размером 200 МБ)
  2. Сделайте еще три копии этого меньшего jpeg, повернув каждую на 90 градусов.
  3. Отправьте каждую из этих четырех ориентаций в API облачного машинного обучения (мне повезло с Microsoft в прошлом)
  4. Проанализируйте ответы. Выбрали наиболее подробные и/или с наибольшей достоверностью как правильную ориентацию.
  5. Поверните исходный полноразмерный скан на соответствующую величину и удалите четыре меньших файла JPEG.

Я проверил это с помощью одного сканирования, и в моем случае n = 1 API имел гораздо более длинный список тегов и лучшую (и более длинную) предлагаемую подпись для правильной ориентации.

Потенциальные проблемы:

  1. Облачный провайдер может прекратить использование API или начать брать больше, чем мы можем себе позволить (когда я написал сценарий для теста создания метаданных с использованием пакета этих карт, уровень использования оставался в категории бесплатных).
  2. Я думаю, что Microsoft уже может повернуть изображение, которое вы отправляете, для целей OCR (чтобы поймать слова, написанные в любой ориентации), если они начнут применять более обобщенный ИИ метаданных ко всем ориентациям, тогда это может перестать работать (хотя можно надеяться, что они добавил бы ключ в ответ для наилучшего предположения ориентации).
  3. (В моей ситуации) на открытках часто есть надписи с ориентацией, не соответствующей изображению (названия фотостудий и т. д.). Если они не делают вышеперечисленного, как я подозреваю, то лучшее распознавание текста за один оборот может обмануть сценарий. Возможно, придется игнорировать результаты OCR, если это окажется проблемой.
  4. Использует пропускную способность.
person pr3sidentspence    schedule 07.11.2018
comment
Отличное мышление. Вы также можете попробовать использовать Amazon Rekognition для анализа изображений. - person Tapas Bose; 08.11.2018
comment
@TapasBose Спасибо! Я еще не пробовал это. Я протестировал предложения Microsoft, Google и IBM. Microsoft кажется лучшим из них на данный момент. - person pr3sidentspence; 10.11.2018
comment
@TapasBose Я написал это в Powershell: gist.github.com/pr3sidentspence/ он получает больше всего из них прав. - person pr3sidentspence; 15.12.2018
comment
Забыл упомянуть, что для этого требуется ImageMagick 7+ (меньше, если вы измените magick.exe на IMPATH\convert.exe) - person pr3sidentspence; 15.12.2018
comment
Спасибо за усилия :) - person Tapas Bose; 15.12.2018
comment
Это было из корыстных соображений, хлопотно проверять каждую открытку вручную. :) - person pr3sidentspence; 16.12.2018
comment
Он сильно провалился на открытках с текстовым оформлением (не наше изображение, но это бывший. manitobaphotos. com/Postcards/top.jpg ), поэтому я добавляю некоторые проверки, которые пропускают такие карточки (мне приходится использовать такие ключевые слова, как текст, подпись и книга в тегах и подписях, чтобы отсеять их. Я' У меня получилось пропустить большинство из них, и я надеюсь, что в будущем он переключится на наилучшие результаты OCR (OCR тоже испытывает трудности со словом art, но часто сопровождающий текст более прямолинеен). - person pr3sidentspence; 19.12.2018
comment
Можно ли применить машинное обучение, когда система может научиться различать словесное искусство и не-словесное искусство? - person Tapas Bose; 19.12.2018
comment
@TapasBose Я бы так подумал, но вам потребуются тысячи обучающих наборов, по крайней мере, так мне сказал кто-то, кто работал над сервисом быстрого развертывания машинного обучения Amazon, Deep Learning AMI ( aws.amazon.com/machine-learning/amis ). Я думаю, что это выше моего понимания прямо сейчас. - person pr3sidentspence; 21.12.2018
comment
@TapasBose А теперь я устанавливаю тензорный поток... спасибо :) - person pr3sidentspence; 21.12.2018
comment
Я очень рад ???? - person Tapas Bose; 21.12.2018
comment
Пожалуйста, дай мне знать - person Tapas Bose; 22.12.2018
comment
Это странно, клянусь, это статья, на которую я ссылался, когда упоминал о выпрямлении слегка перекошенных изображений, но в ней обсуждается, как применять машинное обучение именно к этой проблеме: d4nst.github.io/2017/01/12/ориентация изображения - person pr3sidentspence; 23.03.2019