Правильный ли код образца setDisplayOrientation?

17

Страница документации для Camera.setDisplayOrientation содержит следующий код что использование его «сделает изображение камеры показанным в той же ориентации, что и дисплей»:

 public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }

Однако у меня были проблемы с его использованием, иногда изображение выглядело с ног на голову. После некоторой пробной ошибки я обнаружил, что правильный код будет (заменяем последние 8 строк метода):

    int result = (360 + info.orientation - degrees) % 360;
    camera.setDisplayOrientation(result);

(Это означает, что расчет для обратных камер также подходит для фронтальных камер). Комментарий «компенсировать зеркало» немного странный, поскольку зеркалирование не может быть отменено путем вращения, эта операция сворачивает только повороты на 90 ° и 270 ° что на самом деле не имеет смысла для меня.

Итак, вопрос: действительно ли образец неправильный или я что-то не хватает? Я пробовал его на нескольких устройствах, как на задних, так и на фронтальных камерах и на всех поддерживаемых ориентациях, поэтому я знаю, что мой код работает. Одна маленькая деталь, о которой можно было бы упомянуть: все мои устройства вернулись на 90 ° как info.orientation .

EDIT: Здесь - мой код, связанный с камерой, я проверил его на Nexus One и Samsung Galaxy S Plus. Он используется в моем 3D-приложении для отслеживания головы , предварительный просмотр показан в нижний левый угол и всегда должен иметь правильную ориентацию.

РЕШЕНИЕ (вроде): Похоже, что код верен, но мой тестовый телефон (Samsung Galaxy S Plus) возвращает неверное значение для камеры CameraInfo.orientation. Существует много связанных дискуссий о том, что предварительный просмотр отображается вверх дном на этой модели (примеры здесь и здесь ). Способ исправления состоит в том, чтобы включить возможность поворота изображения вручную.

    
задан Márton Molnár 27.10.2012 в 20:42
источник
  • К сожалению, в документах Android было много ошибок, но они улучшаются. Я проверил ваш код и испытал то же самое, что и на моих устройствах. Я предлагаю вам перейти сюда: code.google.com/p/android/issues/... –  Richard Taylor 30.10.2012 в 11:36

1 ответ

13

Отказанный фрагмент, который я использовал и применял в моем проекте, не является проблемой в моих обстоятельствах.

Для всех устройств (Galaxy Note, Galaxy S III, Galaxy Nexus, Galaxy Ace II, Nexus S), которые я использовал для теста, info.Orientation все возвращают 270 на фронтальную камеру и 90 на задней камере.

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

Для неправильной ориентации в предварительном просмотре камеры, пожалуйста, обратитесь к этому решению:

Решение для неправильной ориентации в предварительном просмотре камеры:

Сначала убедитесь, что info.Orientation вернет 270 на переднюю камеру, 90 на задней камере. Затем попробуйте настроить режим предварительного просмотра камеры (или аналогичный класс, который обрабатывает предварительный просмотр), в альбомную.

Таким образом, когда вы просматриваете код, вы найдете:

degree = 90 для ориентации экрана, info.Orientation = 270 для передней камеры. Затем вы получите result = (270 - 90 + 360) % 360 , result = 180 , что означает, что он будет поворачивать часы 180 для вашего фронтального обзора камеры, что позволит исправить проблему перевернутой передней камеры.

Решение для неправильной ориентации в результатах фотосъемки камеры:

Если этот info.Orientation относится к вам, проблема может быть:

  1. Для некоторых устройств Samsung (или других) (например, Galaxy Note, Galaxy SIII) камера будет записывать только Ориентировочный тег вместо вращения реальных пикселей.
  2. Если вы используете переднюю камеру и используете вышеприведенный код, она отображает предварительный просмотр с правильной ориентацией, но при отображении снимка будет отображаться изображение «вверх ногами».

Решение:

/**
 *
 * Get the orientation from EXIF
 * @param filepath
 * @return orientation
 */
public int getExifOrientation(String filepath) {
    int degree = 0;
    ExifInterface exif = null;
    try {
        exif = new ExifInterface(filepath);
    } catch (IOException ex) {
        Log.e("EXIF info", "cannot read exif", ex);
    }
    if (exif != null) {
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
        if (orientation != -1) {
            // We only recognize a subset of orientation tag values.
            switch(orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                degree = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                degree = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                degree = 270;
                break;
            }
        }
    } else {
        degree = 1;
    }
    Log.i("EXIF info", "Orientation degrees: " + degree);
    return degree;
}

Тогда

if (isFromCamera) {

    if (fromFrontCam) {
        // try change here if the orientation still wrong, -90 means rotate counter-clockwise 90 degrees.
        matrix.preRotate(-90);
     } else {
        matrix.preRotate(90);
     }
} else {
    // read EXIF data
    getExifOrientation(path)
    // don't forget to handle the situation that some devices won't write exif data
    matrix.preRotate(degree);
}
    
ответ дан dumbfingers 01.11.2012 в 12:58
  • Спасибо за ваш ответ. Первая строка очень интересная (вы говорите, что образец работает на вас), но остальное не имеет значения, извините. Метод в моем вопросе (Camera.setDisplayOrientation ()) не влияет на порядок массива байтов, переданный в onPreviewFrame (байт [], камера), изображения JPEG или записанные видео ». Я не хочу фотографировать или загружать их, мне нужен только предварительный просмотр в правильной ориентации. –  Márton Molnár 01.11.2012 в 13:09
  • @ MártonMolnár Да, метод Document работает для меня, я могу получить правильную ориентацию на предварительном просмотре камеры. Могу ли я спросить, какое устройство вы используете? Поскольку ваш вопрос заключается в том, чтобы спросить о ориентации предварительного просмотра, я также обновлю свой ответ, извините, что я не полностью понял ваш вопрос поначалу :) –  dumbfingers 01.11.2012 в 13:13
  • @ MártonMolnár, могу ли я взглянуть на то, как вы применяете код в своем проекте? i.e, где вы назвали этот метод? спасибо –  dumbfingers 01.11.2012 в 13:16
  • @ MártonMolnár согласно моему опыту, вы должны настроить свою активность (в свою камеру) на Пейзаж. –  landry 06.11.2012 в 09:17
  • @ MártonMolnár thx, но я думаю, что у меня все еще есть способ помочь, так как U've сказал, что вы установили представление через код, тогда вы могли бы попробовать: setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); чтобы настроить активность камеры (например, @landry, это то, что я пытался сказать вам) в альбом. Надеюсь, вы поняли мои расчеты в моем предыдущем комментарии. –  dumbfingers 06.11.2012 в 10:26
Показать остальные комментарии