Предварительный просмотр камеры Android выглядит странно

Я реализую приложение для камеры, и когда я смотрю предварительный просмотр (особенно с передней камерой), изображение очень толстое. Похоже, изображение растягивается горизонтально. Я следую примеру 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; } } 

Solutions Collecting From Web of "Предварительный просмотр камеры Android выглядит странно"

Предварительный просмотр камеры всегда заполняет SurfaceView показывая его. Если соотношение сторон m_surfaceView не соответствует формату изображения камеры, предварительный просмотр будет растянут.

Вам нужно будет создать m_surfaceView соответствующий соотношению сторон. Это означает, что вам нужно создать его из кода, а не из XML-файла макета.

Существует пример проекта APIDemos, который вы найдете в примерах проектов Android. В проекте есть вещь CameraPreview . У этого есть хорошая демонстрация для настройки предварительного просмотра камеры в SurfaceView . Он имеет класс, который extends ViewGroup и добавляет SurfaceView качестве своего дочернего SurfaceView из кода. Метод onMeasure() был переопределен для определения высоты и ширины SurfaceView , поэтому соотношение сторон сохраняется. Взгляните на проект, и я надеюсь, что это будет ясно.

[Извините, я не мог опубликовать ссылку здесь – это должна быть ссылка, но я нашел ее сломанной. Но если вы установили образцы проектов с Android SDK, вы можете найти проект в образцах. Откройте новый проект Android Sample, выберите APIDemos, затем найдите класс с именем CameraPreview . Насколько я помню, он должен быть в пакете com.example.android.apis.graphics .]

Я изменил метод 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); } } } 

У меня проблема с слишком растягивающим предварительным просмотром камеры. Он слишком растягивается в вертикальном и ландшафтном режимах.

Таким образом, в манифесте я добавил screenOrentation = «Портрет», но это не помогло, но предварительный просмотр перемасштабирован в любой позиции (вертикальный – предварительный просмотр – слишком большой или слишком длинный), вы можете видеть это на экранах. Я бы хотел добавить в 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) { Ld("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) { Ld("Podgląd nie istnieje"); } try { mCamera.stopPreview(); mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { Ld("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

Я уже решил проблему. Что может вызвать проблемы со странным предварительным просмотром камеры.

  • Строка состояния принимает пробелы – вы можете скрыть ее Скрытие строки состояния

  • Некоторые пробелы также принимают TitleBar – вы можете отключить это в манифесте

Android: тема = "@ андроид: стиль / Theme.NoTitleBar">

  • Измененная ориентация активности на пейзаж «beacuse camera preview поддерживают эту ориентацию» – вы можете проверить это на демо-версии API Graphics-> CameraPreview

  • Алгоритм, который сравнивает размер Display.getWidth () Camera.getParameters size (). GetSupportedPreviewSizes (); Если они одинаковы, это функция изменения поверхностиChanged 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) { Ld("Podgląd nie istnieje"); } try { mCamera.stopPreview(); mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { Ld("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; }