Верен ли пример кода setDisplayOrientation?

страница документации для 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 передней камеры. Существует множество связанных дискуссий по поводу отображения предварительного просмотра в перевернутом виде на этой модели (примеры здесь и здесь). Способ исправить это включить опцию ручного поворота изображения.


person molnarm    schedule 27.10.2012    source источник
comment
К сожалению, в документах Android было много ошибок, но они исправляются. Я протестировал ваш код и испытал на своих устройствах то же самое, что и вы. Я предлагаю вам перейти сюда: code.google.com/p/ android/проблемы/   -  person Richard Taylor    schedule 30.10.2012


Ответы (1)


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

Для всех устройств (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);
}
person dumbfingers    schedule 01.11.2012
comment
Спасибо за Ваш ответ. Первая строчка очень интересна (вы говорите, что образец у вас работает), а остальное неактуально, извините. Метод в моем вопросе (Camera.setDisplayOrientation()) не влияет на порядок массива байтов, передаваемого в onPreviewFrame(byte[], Camera), изображениях JPEG или записанных видео. Я не хочу делать снимки или загружать их, мне нужен только предварительный просмотр в правильной ориентации. - person molnarm; 01.11.2012
comment
@MártonMolnár Да, метод документа работает для меня, я могу получить правильную ориентацию при предварительном просмотре камеры. Могу я спросить, какое устройство вы используете? Поскольку ваш вопрос заключается в том, чтобы спросить об ориентации предварительного просмотра, я также обновлю свой ответ, извините, я сначала не полностью понял ваш вопрос :) - person dumbfingers; 01.11.2012
comment
@MártonMolnár, могу я взглянуть, как вы применяете код в своем проекте? то есть где вы вызвали этот метод? Спасибо - person dumbfingers; 01.11.2012
comment
Я добавил детали, которые вы просили. - person molnarm; 02.11.2012
comment
@MártonMolnár, не могли бы вы попробовать установить альбомную ориентацию макета предварительного просмотра? Это будет иметь смысл. - person dumbfingers; 02.11.2012
comment
Это пейзаж, когда устройство. Пожалуйста, попробуйте мое приложение и посмотрите, подходит ли вам предварительный просмотр. - person molnarm; 05.11.2012
comment
@MártonMolnár Конечно, я иду в магазин Play. - person dumbfingers; 05.11.2012
comment
@MártonMolnár Я хотел исправить ориентацию предварительного просмотра камеры в XML на альбомную? Потому что единственная разница между вашим и моим кодом — это ориентация в XML, я думаю. Если вы установите альбомную ориентацию, degree=90 для экрана, info.orientation=270 для передней камеры, result=(270-90+360)%360=180 просто исправьте перевернутое положение. - person dumbfingers; 05.11.2012
comment
@MártonMolnár, согласно моему опыту, вы должны установить для своей деятельности (в которой находится ваша камера) альбомный режим. - person landry; 06.11.2012
comment
Я устанавливаю LayoutParams SurfaceView из кода, именно для этого используется переменная swapMetrics в коде в pastebin. - person molnarm; 06.11.2012
comment
Я дал вам награду, потому что вы пытались мне помочь, но это все еще не совсем ответ :D - person molnarm; 06.11.2012
comment
@MártonMolnár, спасибо, но я думаю, что у меня все еще есть способ помочь, поскольку вы сказали, что устанавливаете вид с помощью кода, тогда не могли бы вы попробовать: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); установить активность камеры (как сказал @landry, это то, что я пытался скажу вам) к пейзажу. Надеюсь, вы поняли мой расчет в моем предыдущем комментарии. - person dumbfingers; 06.11.2012
comment
Я попробовал свое приложение на Galaxy SIII друга, и вы были правы, мой код переворачивает изображение, и образец правильный! Но на моем Galaxy S Plus все наоборот, потому что, как я писал в своем вопросе, он возвращает 90 в качестве информации.ориентация для обеих камер. Ну, что теперь? - person molnarm; 29.11.2012
comment
@MártonMolnár, может быть, вы можете попробовать использовать if (front orientation=90 && back orientation=90), а затем сделать корректирующий расчет? Это происходит только на Galaxy S Plus? - person dumbfingers; 29.11.2012
comment
К сожалению, первая часть не обязательно верна, поскольку самым известным устройством является Nexus 5x. Иногда CameraInfo.ориентация не 270 на передней камере и 90 на задней камере, и ваш код должен справиться с этим. Для таких устройств, как Samsung Galaxy S Plus, требуются специальные прокладки для исправления ошибок прошивки. - person Alex Cohn; 18.08.2020