17

チュートリアルに基づいてカメラアプリを作成しました。私が使用するプレビュー クラスは、api-Demos「CameraPreview」からのものです。ここから変更を加えました(プレビューは常に 90° 回転していました)。だから、これは私がプレビューサイズを設定する方法です:

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // Now that the size is known, set up the camera parameters and begin
    // the preview.
    Camera.Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

    if (display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
        mCamera.setDisplayOrientation(90);
    }

    if (display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    }

    if (display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
    }

    if (display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        mCamera.setDisplayOrientation(180);
    }
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

    requestLayout();

    mCamera.setParameters(parameters);
    mCamera.startPreview();
}

しかし、プレビューが間違った縦横比で表示されます。上記のコードのせいですか、それとも私が使用しているレイアウトのせいですか?:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<Button
    android:id="@+id/button_capture"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true" 
    android:text="@string/capture" />

<FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="100dp"
    android:layout_height="match_parent"/>

では、正しい縦横比を取得するにはどうすればよいでしょうか。前もって感謝します。

PS i read the answer from: Android カメラのプレビューが奇妙に見える しかし、これは私にとってはうまくいきません。

4

5 に答える 5

25

この関数を追加して、プレビュー サイズを変更してみてください。

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.05;
    double targetRatio = (double) w/h;

    if (sizes==null) return null;

    Camera.Size optimalSize = null;

    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Find size
    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;
}

そして、これらの最適化された値からサイズを設定します。

List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);

parameters.setPreviewSize(optimalSize.width, optimalSize.height);
于 2013-07-23T08:12:54.107 に答える
3

上記のソリューションを使用して、private Size getOptimalPreviewSize(List size, int w, int h) メソッドを使用します。うまくいきました!縦向きの縦横比に問題がありました。これが私の解決策です。それをアンドロイドのドキュメントと混ぜる:

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.

            if (mHolder.getSurface() == null){
              // preview surface does not exist
              return;
            }


            // stop preview before making changes
            try {
                mCamera.stopPreview();
            } catch (Exception e){
              // ignore: tried to stop a non-existent preview
            }

            // set preview size and make any resize, rotate or
            // reformatting changes here
            Camera.Parameters params = mCamera.getParameters();
            params.set("orientation", "portrait");
            Size optimalSize=getOptimalPreviewSize(params.getSupportedPreviewSizes(),  getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
            params.setPreviewSize(optimalSize.width, optimalSize.height);
            mCamera.setParameters(params);
            // start preview with new settings
            try {

                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();

            } catch (Exception e){
                Log.d(TAG, "Error starting camera preview: " + e.getMessage());
            }
        }
    }
于 2014-04-23T09:16:26.510 に答える
3

問題は、物事をレイアウトする方法にあります。クラスでオーバーライドonLayoutされます。Previewその作業のアイデアは、SurfaceView見つかった最適に従って子のサイズを設定することSizeです。ただし、回転は考慮されていないため、自分で行う必要があります。

  if (mPreviewSize != null) {
    previewWidth = mPreviewSize.height;
    previewHeight = mPreviewSize.width;
  }

それ以外の

  if (mPreviewSize != null) {
    previewWidth = mPreviewSize.width;
    previewHeight = mPreviewSize.height;
  }

トリックは、によって達成される90度の回転のために行われる幅と高さを交換することです

  mCamera.setDisplayOrientation(90);

設定した向きに応じて、子プレビューのサイズ設定をフォークすることも検討してください。

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
      //...
  }

(私が提供するコードでは、常に 90 度の回転です。180 度の場合は何もする必要はありません。回転を設定しない場合は、幅と高さを交換する必要はありません)

言及する価値のあるもう1つのこと-回転があり、子の幅と高さを交換する場合を計算するときは、parent( ) width and height swapped ingetOptimalPreviewSizeも渡す必要があります。PreviewonMeasure

if (mSupportedPreviewSizes != null) {
  //noinspection SuspiciousNameCombination
  final int previewWidth = height;
  //noinspection SuspiciousNameCombination
  final int previewHeight = width;
  mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight);
}
于 2015-10-26T18:46:23.327 に答える
1

ヘンリックの答えはうまくいかなかったので、ターゲットビューの現在の幅と高さ、およびアクティビティの向きを考慮して、カメラの最適なプレビューサイズを決定する別の方法を作成しました。

public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) {
    if (CommonUtils.isEmpty(cameraPreviewSizes)) {
        return null;
    }

    int optimalHeight = Integer.MIN_VALUE;
    int optimalWidth = Integer.MIN_VALUE;

    for (Camera.Size cameraPreviewSize : cameraPreviewSizes) {
        boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width;
        int actualCameraWidth = cameraPreviewSize.width;
        int actualCameraHeight = cameraPreviewSize.height;

        if (isActivityPortrait) {
            if (!isCameraPreviewHeightBigger) {
                int temp = cameraPreviewSize.width;
                actualCameraWidth = cameraPreviewSize.height;
                actualCameraHeight = temp;
            }
        } else {
            if (isCameraPreviewHeightBigger) {
                int temp = cameraPreviewSize.width;
                actualCameraWidth = cameraPreviewSize.height;
                actualCameraHeight = temp;
            }
        }

        if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) {
            // finds only smaller preview sizes than target size
            continue;
        }

        if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) {
            // finds only better sizes
            optimalWidth = actualCameraWidth;
            optimalHeight = actualCameraHeight;
        }
    }

    Size optimalSize = null;

    if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) {
        optimalSize = new Size(optimalWidth, optimalHeight);
    }

    return optimalSize;
}

Android のSizeは API 21 以降で使用できるため、これはカスタム Size オブジェクトを使用します。

public class Size {

    private int width;
    private int height;

    public Size(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

}

グローバル レイアウトの変更をリッスンしてビューの幅と高さを決定し、新しい寸法を設定できます。これは、アクティビティの方向性をプログラムで決定する方法も示しています。

cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // gets called after layout has been done but before display.
                cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);

                boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
                Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait);
                if (optimalCameraPreviewSize != null) {
                    LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight());
                    cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams);
                }
            }
        });
于 2015-08-05T12:53:39.957 に答える