2012-10-05 157 views
5

我正在實現一個相機應用程序,當我看預覽(尤其是前置相機)時,圖像非常胖。它看起來像圖像水平延伸。我遵循最佳相機尺寸的sdk示例,但它沒有幫助。如何調整我的相機設置,以便像其他相機應用一樣進行預覽?Android相機預覽看起來很奇怪

謝謝。

我的代碼如下。

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

} 

回答

15

相機預覽總是充滿了SurfaceView顯示它。如果m_surfaceView的寬高比與相機的寬高比不匹配,則預覽將被拉伸。

您需要創建與縱橫比相匹配的m_surfaceView。這意味着,您需要從代碼創建它,而不是從佈局XML文件創建。

有一個示例項目APIDemos你可以在android示例項目中找到它。在該項目中有一個名爲CameraPreview的東西。這一個在SurfaceView中有一個很好的演示來設置相機預覽。它有一個類extends ViewGroup,並在代碼中添加SurfaceView作爲其子代。 onMeasure()方法已被覆蓋以確定SurfaceView的高度和寬度,因此縱橫比將被保留。看看這個項目,我希望它會很清楚。

[抱歉,我無法在此發佈鏈接 - this應該是鏈接,但我發現它已損壞。但是,如果您已經使用Android SDK安裝了示例項目,則可以在示例中找到該項目。打開一個新的Android示例項目,選擇APIDemos,然後查找名爲CameraPreview的類。據我所知,它應該在包com.example.android.apis.graphics。]

+0

謝謝很多!我會嘗試。 –

+2

這是怎麼可能的,任何設備的普通相機有一個全屏預覽,沒有任何拉伸呢? – idish

+0

我在sdk/sample/adroid-18裏面找到了。謝謝 –

0

我改變了onLayout方法,而不是相機預覽不拉伸。其餘的東西與APiDemo相同,它在這裏找到sdk/sample/adroid-18.這個想法是我們只有一些支持的預覽大小,但是我們的視圖大小可能並不總是與預覽大小匹配。所以我採取更大的預覽大小,然後我的圖像視圖大小。這個對我有用。可以幫助別人..

@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); 
      } 
     } 
    } 
+0

什麼可能是左,右,下和上,他們在哪裏宣佈?同樣的l,r,t,b? – desgraci

+0

其重寫的方法,你不需要傳遞值。根據你的佈局,它將需要l,r,t,b值 –

0

我有太拉伸相機預覽的問題。 這是太拉伸在垂直和風景模式。

因此,在清單我加入screenOrentation =「肖像」, 但它並沒有幫助,還預覽在 重新調整的任何位置(垂直 - 預覽是寬或 景觀太長),你可以 看到這個在屏幕。 我想三星王牌添加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; 
    } 
} 

}

Link to screens and project doing at eclipse

0

我已經解決了問題。什麼可能導致奇怪的相機預覽問題。

  • 狀態欄需要空間 - 你可以將其隱藏Hiding the Status Bar

  • 一些空間也採取TitleBar中 - 你可以在清單

安卓關閉此:主題=「@ android:style/Theme.NoTitleBar「>

  • 更改活動方向爲橫向「怎麼一回事,因爲攝像頭預覽支持,傾向」 - 你可以在API demo圖形 - > CameraPreview

  • 算法比較Display.getWidth的尺寸(檢查)Camera.getParameters大小()。 getSupportedPreviewSizes();如果它們是相同的是surfaceChanged變化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; 
    } 
相關問題