6

カメラアプリを実装していますが、プレビューを見ると(特にフロントカメラで)、画像が非常に太くなっています。画像が横に引き伸ばされているように見えます。最適化されたカメラ サイズで sdk サンプルに従いますが、役に立ちません。他のカメラ アプリと同じようにプレビューできるようにカメラ設定を調整するにはどうすればよいですか?

ありがとう。

私のコードは以下です。

public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback {

Camera m_camera;
SurfaceView m_surfaceView;
int m_numOfCamera;
int m_defaultCameraId;
int m_currentCamera;
int m_surfaceWidth;
int m_surfaceHeight;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera);
    getActionBar().setDisplayHomeAsUpEnabled(true);


    m_surfaceView = (SurfaceView)findViewById(R.id.cameraPreview);
    m_surfaceView.getHolder().addCallback(this);

    m_camera = Camera.open();

    m_numOfCamera = Camera.getNumberOfCameras();

    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < m_numOfCamera; ++i) {
        Camera.getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            m_defaultCameraId = i;
            m_currentCamera = m_defaultCameraId;
        }       
    }

    if (m_numOfCamera < 1) {
        MenuItem switchCam = (MenuItem)findViewById(R.id.menu_switch_camera);
        switchCam.setVisible(false);
    }
}

@Override
public void onPause() {
    super.onPause();
    m_camera.stopPreview();
}

@Override
public void onDestroy() {
    super.onDestroy();
    m_camera.release();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_camera, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) 
{
    if (item.getItemId() == android.R.id.home) 
    {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);

        return true;
    } 
    else if (item.getItemId() == R.id.menu_switch_camera)
    {
        if (m_camera != null) {
            m_camera.stopPreview();
            m_camera.release();
            m_camera = null;
        }   

        m_camera = Camera.open((m_currentCamera + 1) % m_numOfCamera);
        m_currentCamera = (m_currentCamera + 1) % m_numOfCamera;

        Camera.Parameters params = m_camera.getParameters();
        List<Camera.Size> sizes = params.getSupportedPreviewSizes();
        Camera.Size size = getOptimalPreviewSize(sizes, m_surfaceWidth, m_surfaceHeight);

        params.setPreviewSize(size.width,  size.height);

        m_camera.setParameters(params);
        setCameraDisplayOrientation(this, m_currentCamera, m_camera);
        m_camera.startPreview();
        try {
            m_camera.setPreviewDisplay(m_surfaceView.getHolder());
        } catch (Exception e) {
            e.printStackTrace();
        }   
        return true;
    }
    return true;
}

public void onPictureTaken(byte[] arg0, Camera arg1) {
    // TODO Auto-generated method stub

}

public void onShutter() {
    // TODO Auto-generated method stub

}

public void surfaceChanged(SurfaceHolder arg0, int format, int w, int h) {
    m_surfaceWidth = w;
    m_surfaceHeight = h;
    Camera.Parameters params = m_camera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size selected = getOptimalPreviewSize(sizes, w, h);

    params.setPreviewSize(selected.width,  selected.height);


    m_camera.setParameters(params);
    setCameraDisplayOrientation(this, m_currentCamera, m_camera);
    m_camera.startPreview();    
}

private 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);
 }


public void surfaceCreated(SurfaceHolder arg0) {
    try {
        m_camera.setPreviewDisplay(m_surfaceView.getHolder());
    } catch (Exception e) {
        e.printStackTrace();
    }   
}

public void surfaceDestroyed(SurfaceHolder arg0) {
    // TODO Auto-generated method stub

}

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {


    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) w / h;
    if (sizes == null)
        return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (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);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }

    return optimalSize;
}

}
4

4 に答える 4

16

カメラプレビューは常に表示をいっぱいにしSurfaceViewます。のアスペクト比がm_surfaceViewカメラのアスペクト比と一致しない場合、プレビューは引き伸ばされます。

m_surfaceViewアスペクト比に合わせて作成する必要があります。つまり、レイアウトXMLファイルからではなく、コードから作成する必要があります。

AndroidサンプルプロジェクトにあるサンプルプロジェクトAPIDemosがあります。プロジェクトには、という名前のものがありCameraPreviewます。これは、でカメラプレビューを設定するための優れたデモンストレーションですSurfaceView。のクラスがあり、コードから子としてextends ViewGroupを追加します。SurfaceViewこのonMeasure()メソッドは、の高さと幅を決定するためにオーバーライドされているSurfaceViewため、アスペクト比は保持されます。プロジェクトを見てください、そしてそれが明確になることを願っています。

[申し訳ありませんが、ここにリンクを投稿できませんでした。これはリンクであるはずですが、壊れていることがわかりました。ただし、Android SDKを使用してサンプルプロジェクトをインストールした場合は、サンプルでプロジェクトを見つけることができます。新しいAndroidサンプルプロジェクトを開き、APIDemosを選択して、という名前のクラスを探しますCameraPreviewcom.example.android.apis.graphics私が覚えている限り、それはパッケージに含まれているはずです。]

于 2012-10-05T17:29:31.033 に答える
1

onLayout メソッドを変更しましたが、カメラのプレビューは引き伸ばされません。残りの部分は、ここ sdk/sample/adroid-18 にある APiDemo と同じです。サポートされているプレビューのサイズは一部しかありませんが、ビューのサイズが常にプレビューのサイズと一致するとは限りません。そのため、イメージビュー サイズよりも大きいプレビュー サイズを使用しました。わたしにはできる。誰かを助けるかもしれません..

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

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

            // Center the child SurfaceView within the parent.
            if (width * previewHeight < height * previewWidth) {

                final int scaledChildWidth = previewWidth * height
                        / previewHeight;

                left = (width - scaledChildWidth) / 2;
                top = 0;
                right = (width + scaledChildWidth) / 2;
                bottom = height;

                child.layout(left, top, right, bottom);
            } else {
                final int scaledChildHeight = previewHeight * width
                        / previewWidth;

                left = 0;
                top = (height - scaledChildHeight) / 2;
                right = width;
                bottom = (height + scaledChildHeight) / 2;

                child.layout(left, top, right, bottom);
            }
        }
    }
于 2014-01-21T11:26:39.900 に答える
0

カメラのプレビューを引き伸ばしすぎると問題が発生します。縦と横モードで伸びすぎです。

したがって、マニフェストで screenOrentation="Portrait" を追加しましたが、それは役に立ちませんでした。プレビューは任意の位置で再スケーリングされます (垂直 - プレビューが広すぎるか、横が長すぎます)。これは画面で確認できます。Samsung ace IIIではすべて問題ありませんが、LG Nexus 4では伸びています

 package pl.probs.camera.component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import pl.probs.lib.debug.L;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private static final String TAG = "CameraPreview";
    private static boolean showLogs = true;
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Context context;
    private Parameters resolution;
    private List<Size> lSuportedPreviewSize;
    private static int cOrientation = 0; // aktualny kat orientacji
    private static boolean cOrientationChanged = false; // Stan orientacji
                                                        // zostal zmieniony
                                                        // wzgledem poprzedniego
    private Display display; // Rozmiar ekranu
    private Point displaySize; // Zmienna przechowuje Rozmiar Ekranu
    private Point optimalPreviewSize;
public CameraPreview(Context context, Camera camera, int resolution) {
    super(context);
    this.optimalPreviewSize = new Point();
    this.context = context;
    this.mCamera = camera;
    setDisplaySize(this.display);
    setFocusable(true);
    setFocusableInTouchMode(true);
    mHolder = getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    this.resolution = getMinResolution(resolution);
    this.optimalPreviewSize = getOptimalPreviewResolution(this.display);
    Size s = mCamera.getParameters().getPreviewSize(); // Sprawdzenie jaki
                                                        // prewiev ustawiony
}

public Point getOptimalPreviewSize() {
    return optimalPreviewSize;
}

public void surfaceCreated(SurfaceHolder holder) {
    try {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(holder);
            Size s = mCamera.getParameters().getPreviewSize();
            mCamera.startPreview();
        }
    } catch (IOException e) {
        L.d("Błąd ustawiania podglÄ…du: " + e.getMessage());
    }
}

protected void onPause() {
    // Because the Camera object is a shared resource, it's very
    // important to release it when the activity is paused.
    if (mCamera != null) {
        mCamera.release();
        mCamera = null;
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    if (mCamera != null) {
        mCamera.stopPreview();
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    Camera.Parameters setPrevOrientation = mCamera.getParameters();
    if (mHolder.getSurface() == null)
        return;

    try {
        mCamera.stopPreview();
        Size sizeBefore = mCamera.getParameters().getPreviewSize();
        setPrevOrientation.setRotation(setCameraDisplayOrientation((Activity) context, getCameraId(), mCamera));
        // Orientacja Portrait np 640x480 Landscape 480x640
        this.resolution.setPreviewSize(this.optimalPreviewSize.x, this.optimalPreviewSize.y);
        mCamera.setParameters(this.resolution);
        Size sizeAfter = mCamera.getParameters().getPreviewSize();
    } catch (RuntimeException e) {
        L.d("Podgląd nie istnieje");
    }

    try {
        mCamera.stopPreview();
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

    } catch (Exception e) {
        L.d("błąd podgladu: " + e.getMessage());
    }
}

@SuppressLint("ClickableViewAccessibility")
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        mCamera.autoFocus(new AutoFocusCallback() {

            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                // do something
            }
        });

    }

    return true;
}

private static int 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;
    }

    cOrientation = degrees;

    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);
    return result;
}

private int getCameraId() {
    int cameraId = -1;
    int numberOfCameras = Camera.getNumberOfCameras();
    for (int i = 0; i < numberOfCameras; i++) {
        CameraInfo info = new CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
            cameraId = i;
            break;
        }
    }
    return cameraId;
}

private Parameters getMinResolution(int desireResolutionInMpx) {
    int height[], width[], size;
    float megapixels;
    Camera.Parameters p = mCamera.getParameters();
    size = p.getSupportedPictureSizes().size();
    height = new int[size];
    width = new int[size];
    for (int i = 0; i < size; i++) {
        height[i] = p.getSupportedPictureSizes().get(i).height;
        width[i] = p.getSupportedPictureSizes().get(i).width;
        megapixels = (float) (((float) height[i] * (float) width[i]) / 1024000);
        if (megapixels <= desireResolutionInMpx) {
            p.setPictureSize(width[i], height[i]);
            break;
        }
    }
    return p;
}

private Point getOptimalPreviewResolution(Display displaySize) {
    lSuportedPreviewSize = mCamera.getParameters().getSupportedPreviewSizes();
    Point optimalPreviewSize = new Point();
    int displayWidth = displaySize.getWidth(); // szerokosc ekranu
    int displayHeight = displaySize.getHeight(); // wysokosc ekranu
    int cameraHeight; // wspierana wysokosc kamery
    int cameraWidth; // wspierana szerokosc kamery

    // Lista przechowywujace SupportedPreviewSize kamery, wszyskie
    // rozdzielczosci mniejsze od szerokosc i wysokosci ekranu
    List<Point> lOptimalPoint = new ArrayList<Point>();

    // Pomocniczo do listowania zawartosci listy
    // TODO manta displayHeight cameraHeight brak oraz width brak zgodnosci
    // (
    System.out.println(lOptimalPoint.toString());
    for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
        Log.i(TAG, "w " + lSuportedPreviewSize.get(i).width + " h " + lSuportedPreviewSize.get(i).height + " \n");
    }

    // Wyszukanie wszystkich wysokosci kamery mniejszej od wysokosci ekranu
    for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
        // TODO Uwazaj kamera zapisuje swoj rozmiar dla pozycji landscape
        // gdzie height = 480 a width = 800
        cameraHeight = lSuportedPreviewSize.get(i).width;
        cameraWidth = lSuportedPreviewSize.get(i).height;
        // Porownaj wysokosc ekranu urzadzenia z wysokosci supportedPreview
        // dodaj do listy
        if (displayHeight > cameraHeight) {
            lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
        }
    }

    // Sortowanie rosnaco
    Collections.sort(lOptimalPoint, new ComapreSupportedPreviewByWidth());
    // Ostatni element listy optymalny
    optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size()-1);

    // Zwracana rozdzielczosc landscape aparatu np (800x600)
    return optimalPreviewSize;
}

private void setDisplaySize(Display display) {
    Activity activity = (Activity) this.context; // Pobierz aktywnosc aby
                                                    // znać rozmiar ekranu

    this.display = activity.getWindowManager().getDefaultDisplay();
}

class ComapreSupportedPreviewByWidth implements Comparator<Point> {

    @Override
    public int compare(Point lhs, Point rhs) {
        return lhs.x - rhs.x;
    }
}

}

eclipse で行う画面とプロジェクトへのリンク

于 2015-07-21T14:41:37.107 に答える
0

私はすでに問題を解決しました。奇妙なカメラ プレビューで問題が発生する原因は何ですか。

  • ステータス バーにはスペースが必要です - 非表示にできます ステータス バーを非表示にする

  • 一部のスペースは TitleBar も使用します - これはマニフェストでオフにできます

android:theme="@android:style/Theme.NoTitleBar">

  • アクティビティの向きを横向きに変更しました。「カメラ プレビューはその向きをサポートしているため」 - これはAPI デモGraphics->CameraPreviewで確認できます。

  • Display.getWidth () Camera.getParameters size () のサイズを比較するアルゴリズム。getSupportedPreviewSizes (); それらが同じ場合は、リストを検索するときに受け取った SurfaceChanged change Parametrs.setPreviewSize (x, y) の関数です


public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    Camera.Parameters setPrevOrientation = mCamera.getParameters();
    if (mHolder.getSurface() == null)
        return;

    try {
        mCamera.stopPreview();
        Size sizeBefore = mCamera.getParameters().getPreviewSize();
        setPrevOrientation.setRotation(setCameraDisplayOrientation(
                (Activity) context, getCameraId(), mCamera));
        // Orientacja Portrait np 640x480 Landscape 480x640
        this.resolution.setPreviewSize(this.optimalPreviewSize.x,
                this.optimalPreviewSize.y);
        mCamera.setParameters(this.resolution);
        Size sizeAfter = mCamera.getParameters().getPreviewSize();
    } catch (RuntimeException e) {

        L.d("Podgląd nie istnieje");
    }

    try {
        mCamera.stopPreview();
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

    } catch (Exception e) {
        L.d("błąd podgladu: " + e.getMessage());
    }
 } 

    private Point getOptimalPreviewResolution(Display displaySize) {

        lSuportedPreviewSize = mCamera.getParameters()
                .getSupportedPreviewSizes();
        Point optimalPreviewSize = new Point();
        int displayWidth = displaySize.getWidth();
        int displayHeight = displaySize.getHeight();
        int cameraHeight;
        int cameraWidth;

        List<Point> lOptimalPoint = new ArrayList<Point>();

        for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
            cameraHeight = lSuportedPreviewSize.get(i).width;
            cameraWidth = lSuportedPreviewSize.get(i).height;
            if (displayHeight >= cameraHeight) {
                lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
            }
        }

        // Sort ascending
        Collections.sort(lOptimalPoint,
                new ComapreSupportedPreviewByWidth());
        // Last element is optimal
        optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size() - 1);

        // Return resolution - camera at landscape mode (800x600)
        return optimalPreviewSize;
    }

    class ComapreSupportedPreviewByWidth implements Comparator<Point> {

    @Override
    public int compare(Point lhs, Point rhs) {
        return lhs.x - rhs.x;
    }
于 2015-08-04T19:48:19.033 に答える