2013-07-23 19 views
14

Stworzyłem aplikację na podstawie samouczka. Klasa podglądu, której używam, pochodzi z api-Demos "CameraPreview". Dodałem modyfikację z here (podgląd zawsze był obracany o 90 °). Tak ustawiłem rozmiar podglądu:Podgląd obrazu z kamery w niewłaściwym formacie

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

Ale podgląd jest wyświetlany przy niewłaściwym współczynniku kształtu. Czy to z powodu powyższego kodu lub prawdopodobnie ze względu na układ używam ?:

<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"/> 

Więc jak uzyskać prawidłowe proporcje? Z góry dziękuję.

P.S. Przeczytałem odpowiedź od: Android camera preview look strange Ale to nie działa dla mnie.

+0

może można zamknąć ten kwestia ? – Poutrathor

+0

dlaczego? co się zmieniło? – dermoritz

+1

najpierw nie musisz wierzyć, 2. Nie mam czasu na wypróbowanie innych rozwiązań (opublikowanych rok po zamieszczeniu pytania). Gdy tylko spróbuję innych odpowiedzi, udzielę informacji zwrotnej. Do tego czasu wszystko jest w porządku ... – dermoritz

Odpowiedz

21

Spróbuj zmienić rozmiary podglądu z dodaniem tej funkcji:

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

i ustawienie rozmiary od tych optymalnych wartości:

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

parameters.setPreviewSize(optimalSize.width, optimalSize.height); 

Mam nadzieję, że to działa :)

poważaniem

Henric

+0

jak stwierdzono w moim pytaniu używam tego kodu (jest to z Api-Demos "CameraPreview"). Myślę, że problem zależy od mojego układu i sposobu dodawania podglądu? – dermoritz

+0

Ta odpowiedź jest całkiem przydatna, powinna być zaakceptowana. – zionpi

+0

@dermoritz To nie jest problem z układem! musisz ustawić parametry jeden z 'mCamera'-object jeden wiersz powyżej' mCamera.startPreview() 'w klasie' CameraPreivew.java'. Pracuje dla mnie. Ta odpowiedź powinna zostać zaakceptowana! – 000000000000000000000

3

Poniższy kod modyfikuje szerokość/wysokość kontenera podglądu kamery w celu dopasowania do współczynnika kształtu podglądu kamery.

1

Korzystanie z powyższego rozwiązania przy użyciu metody private Rozmiar getOptimalPreviewSize (rozmiary list, int w, int h). Dobrze działało! Występowały problemy z proporcjami w orientacji pionowej: tutaj jest to moje rozwiązanie. Zmieszanie go z dokumentacją androida:

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()); 
      } 
     } 
    } 
1

odpowiedź Henric za nie działa dla mnie, więc utworzyliśmy inną metodę, która określa optymalny rozmiar podglądu dla każdej kamery zważywszy na widoku cel bieżącej szerokości i wysokości, a także aktywność orientacja:

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

używa niestandardowych obiektów wielkości, ponieważ Android Size jest dostępny po API 21.

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

} 

można powstrzymać kopiuj szerokość i wysokość widoku, nasłuchując zmian jego globalnego układu, a następnie ustaw nowe wymiary. To również pokazuje, jak programowo określić orientację działania:

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

Problem jest naprawdę w sposobie układania rzeczy. istnieje overriden onLayout w klasie Preview. Ideą jego pracy jest ustawienie rozmiaru dziecka o rozmiarach SurfaceView zgodnie z ustaloną optymalną wartością: Size.ale nie bierze pod uwagę obrót, więc trzeba to zrobić samemu:

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

zamiast

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

Sztuką jest, aby zamienić szerokość i wysokość, która jest wykonywana ze względu na obrót o 90 stopni osiągnięty przez

mCamera.setDisplayOrientation(90); 

można też rozważyć rozwidlone ustawienie rozmiaru podglądu dziecko w zależności od orientacji, które ustawia się w

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

(w dostarczonym przeze mnie kodzie zawsze jest to obrót o 90 stopni, dla 180 nie trzeba nic robić, a gdy nie ustawia się żadnego obrotu, nie ma potrzeby zamiany szerokości i wysokości)

Inną rzeczą warto wspomnieć - przy obliczaniu getOptimalPreviewSize dla przypadku, gdy masz obrót i zamienić szerokość dziecięcej i wysokość również powinien przejść rodzica (Preview) szerokość i wysokość zamienione w onMeasure:

if (mSupportedPreviewSizes != null) { 
    //noinspection SuspiciousNameCombination 
    final int previewWidth = height; 
    //noinspection SuspiciousNameCombination 
    final int previewHeight = width; 
    mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight); 
} 
Powiązane problemy