Androidカメラプレビュー画像のストレッチ変形の解決方法

2770 ワード

ラベル:Androidカメラ
最近しばらくカメラの開発をしていて、いくつかの悟りがあったので、ここで整理して共有します.この過程でも、プレビュー時に画像が引っ張られたり、プレビュー時に画像が回転したりして変形したり、携帯電話を90回転させたときにプレビュー画像が変形したりするなど、多くの問題が発生しました.実は最後の原因は解像度にある.なぜそう言うのか、以下少し分析します.
カスタムカメラは、ユーザーの操作の観点から2つの部分があります.一つは携帯電話の画面を見る画像で、一つはクリックして写真を撮る(特殊な機能がある場合を除き、一般的なカメラを言う).この2本の中で、実はすべて画像と付き合って、携帯電話のスクリーンの上の画像は実は1フレームのハードウェアのカメラがスキャンした結果で、写真をクリックする時このフレームの画像をあるフレームから選びます.
画像といえば質問ですが、「どのような画像表示が正常ですか?「この質問には理解できない人もいれば、どう答えたらいいか分からない人もいるかもしれません.私は答えがあります.正しいかどうか分かりませんが、私は今そう思っています.もし違う意見があれば、伝言を残して、みんなで議論してもいいです.画像が正常に表示されたら、画像の大きさと解像度が一致すると思います.画像の解像度は画素点の多少を表しています.幅3、高さ4の画像があるとします.画像上の画素点は、幅4個、高さ3個です.では、このような場合、画素点で描かれた画像は私たちが望んでいるものではなく、扁平に撮られた画像に違いありません.したがって、カスタムカメラは、適切な解像度をカメラに設定する方法を解決し、画像の幅と関係があるはずです.
では、適切な解像度を選択するとします.Android公式のdemo例には関連コードがあります.
private static Camera.Size getOptimalSize(@NonNull List sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;
    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes) {
      double ratio = (double) size.width / size.height;
      if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
      if (Math.abs(size.height - targetHeight) < minDiff) {
        optimalSize = size;
        minDiff = Math.abs(size.height - targetHeight);
      }
    }

    if (optimalSize == null) {
      minDiff = Double.MAX_VALUE;
      for (Camera.Size size : sizes) {
        if (Math.abs(size.height - targetHeight) < minDiff) {
          optimalSize = size;
          minDiff = Math.abs(size.height - targetHeight);
        }
      }
    }

    return optimalSize;
  }

実は多くの人は、既製のコードがあるので、直接貼っておけばいいと思っています.なぜそんなにたくさん言っているのでしょうか.実はこの方法があって、良いのもここで、悪いのもここで悪いです.注意しなければならないのはこのような行です.
double targetRatio = (double) h / w;

ここのコードはh/wですが、公式の例ではw/hです.公式のdemoではカメラは横方向ですが、私たちが一般的に使っているカメラやカスタムカメラは縦方向です.横向きの設定はAndroid Mainfestですxmlに設定されている
    

上は縦方向に設定されていますが、横方向に設定されていない場合は横方向に設定されています.以上続けて、なぜ公式demoと違うのかというと、実は公式の例が横方向なので、得られたwはhより大きく、私たちのは縦方向なので、wはhより小さいです.これにより、フィルタ解像度エラーが発生します.(ここでwはSurface Viewの幅、hはSurface Viewの高さ、Surface Viewはプレビュー用のコントロール)
上のgetoptimalSize()法で適切な解像度を選択することが解決され、その画像も正常に表示されます.解像度を設定するタイミングが適切であれば、カメラは画像が引っ張られる問題はありません.
ある人は私が直接SurfaceViewの幅を解像度として持つことができるかどうかを言うことができて、私はある携帯電話が実行可能だとしか言えませんが、すべての携帯電話がカスタムの割合を支持しているわけではありません.ある携帯電話は持っているいくつかの割合を支持しています.
Camera.Parameters cameraParameter = camera.getParameters();
cameraParameter.getSupportedPreviewSizes()

これらの解像度の中から選んだほうがいいです