代码之家  ›  专栏  ›  技术社区  ›  Saidur Rahman

相机预览在预览中拉伸/压缩

  •  0
  • Saidur Rahman  · 技术社区  · 7 年前

    我正在做一个项目,从Android摄像头拍摄图像。一切正常。

    但现在面临的一个问题是,当预览显示时,这很好,但在拍摄图像后,两者并非100%相同。拍摄图像后,图像有时会被拉伸或挤压。

    Camerap复习课:

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
        private SurfaceHolder mHolder;
        private Camera mCamera;
        private Context mContext;
        float mDist = 0;
    
        public CameraPreview(Context context, Camera camera) {
            super(context);
            mContext = context;
            mCamera = camera;
            mHolder = getHolder();
            mHolder.addCallback(this);
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
    
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                // create the surface and start camera preview
                if (mCamera == null) {
                    Camera.Parameters params = mCamera.getParameters();
                    if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
                        params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                    }
                    mCamera.setParameters(params);
                    mCamera.setPreviewDisplay(holder);
                    mCamera.startPreview();
                }
            } catch (IOException e) {
                Log.d(VIEW_LOG_TAG, "Error setting camera preview: " + e.getMessage());
            }
        }
    
        public void refreshCamera(Camera camera) {
            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
            // start preview with new settings
            setCamera(camera);
    
            // TODO: don't hardcode cameraId '0' here... figure this out later.
            //setCameraDisplayOrientation(mContext, Camera.CameraInfo.CAMERA_FACING_FRONT, mCamera);
    
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.setDisplayOrientation(90);
                mCamera.startPreview();
            } catch (Exception e) {
                Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
            }
        }
    
        public static void setCameraDisplayOrientation(Context context, int cameraId, Camera camera) {
            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            int rotation = wm.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;
            }
    
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(cameraId, info);
    
            int result;
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                result = (info.orientation + degrees) % 360;
                // Compensate for the mirror image.
                result = (360 - result) % 360;
            } else {
                // Back-facing camera.
                result = (info.orientation - degrees + 360) % 360;
            }
            camera.setDisplayOrientation(result);
        }
    
        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.
            refreshCamera(mCamera);
        }
    
        public void setCamera(Camera camera) {
            //method to set a camera instance
            mCamera = camera;
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            // mCamera.release();
    
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // Get the pointer ID
            Camera.Parameters params = mCamera.getParameters();
            int action = event.getAction();
    
            if (event.getPointerCount() > 1) {
                // handle multi-touch events
                if (action == MotionEvent.ACTION_POINTER_DOWN) {
                    mDist = getFingerSpacing(event);
                } else if (action == MotionEvent.ACTION_MOVE
                        && params.isZoomSupported()) {
                    mCamera.cancelAutoFocus();
                    handleZoom(event, params);
                }
            } else {
                // handle single touch events
                if (action == MotionEvent.ACTION_UP) {
                    handleFocus(event, params);
                }
            }
            return true;
        }
    
        private void handleZoom(MotionEvent event, Camera.Parameters params) {
            int maxZoom = params.getMaxZoom();
            int zoom = params.getZoom();
            float newDist = getFingerSpacing(event);
            if (newDist > mDist) {
                // zoom in
                if (zoom < maxZoom)
                    zoom++;
            } else if (newDist < mDist) {
                // zoom out
                if (zoom > 0)
                    zoom--;
            }
            mDist = newDist;
            params.setZoom(zoom);
            mCamera.setParameters(params);
        }
    
        public void handleFocus(MotionEvent event, Camera.Parameters params) {
            int pointerId = event.getPointerId(0);
            int pointerIndex = event.findPointerIndex(pointerId);
            // Get the pointer's current position
            float x = event.getX(pointerIndex);
            float y = event.getY(pointerIndex);
    
            List<String> supportedFocusModes = params.getSupportedFocusModes();
            if (supportedFocusModes != null
                    && supportedFocusModes
                    .contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
                mCamera.autoFocus(new Camera.AutoFocusCallback() {
                    @Override
                    public void onAutoFocus(boolean b, Camera camera) {
                        // currently set to auto-focus on single touch
                    }
                });
            }
        }
    
        /** Determine the space between the first two fingers */
        private float getFingerSpacing(MotionEvent event) {
            // ...
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return (float)Math.sqrt(x * x + y * y);
        }
    }
    

    下面是使用LinearLayout(@+id/cameraFrame)下的Inner FrameLayout、camera预览的xml布局。

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:baselineAligned="false"
        tools:context=".view.activity.PhotoCaptureActivity">
    
        <RelativeLayout
            android:id="@+id/mainLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginBottom="0dp"
                android:layout_marginLeft="0dp"
                android:layout_marginRight="0dp"
                android:layout_marginTop="0dp"
                android:orientation="horizontal"
                android:weightSum="3">
    
                <FrameLayout
                    android:id="@+id/cameraFrame_layout"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
    
                    <LinearLayout
                        android:id="@+id/cameraFrame"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="horizontal" />
    
                    <ImageView
                        android:id="@+id/captured_image"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical"
                        android:scaleType="fitXY"
                        android:scaleX="-1"
                        />
    
                    <ImageView
                        android:id="@+id/captured_image_back"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical"
                        android:scaleType="fitXY"
                        android:scaleX="-1"
                        android:scaleY="-1"
                        android:visibility="gone"/>
    
                    <ImageButton
                        android:id="@+id/button_capture"
                        android:layout_width="64dp"
                        android:layout_height="64dp"
                        android:layout_gravity="center_horizontal|bottom"
                        android:layout_marginBottom="5dp"
                        android:background="@drawable/ic_camera_capture_image" />
    
                    <ImageButton
                        android:id="@+id/swicth_camera"
                        android:layout_width="36dp"
                        android:layout_height="36dp"
                        android:layout_gravity="right|bottom"
                        android:layout_marginBottom="10dp"
                        android:layout_marginEnd="20dp"
                        android:background="@drawable/ic_camera_switch" />
    
                    <ImageButton
                        android:id="@+id/flash_on"
                        android:layout_width="36dp"
                        android:layout_height="36dp"
                        android:layout_gravity="left|bottom"
                        android:layout_marginBottom="10dp"
                        android:layout_marginStart="20dp"
                        android:background="@drawable/ic_gallery"
                        android:visibility="gone"/>
    
                    <ImageButton
                        android:id="@+id/fab_send_photo"
                        android:layout_width="48dp"
                        android:layout_height="48dp"
                        android:layout_gravity="right|bottom"
                        android:layout_marginBottom="10dp"
                        android:layout_marginEnd="20dp"
                        app:srcCompat="@drawable/ic_send_blue"
                        android:visibility="gone" />
    
                </FrameLayout>
    
            </LinearLayout>
    
        </RelativeLayout>
    </RelativeLayout>
    

    我在google drive中分享了我的活动类、相机预览类和xml文件。 https://drive.google.com/drive/folders/1WETYNhUZiTZOOChzEynRC-cEB6RsYrN5?usp=sharing

    在拍摄图像之前:

    enter image description here

    拍摄图像后:

    enter image description here

    你可以看到,在左边的字母“F”现在是可见的拍摄后的图像。但字母“F”不在预览中。在拍摄图像后,顶栏上的“hp”徽标消失,但“hp”徽标出现在预览中。

    我从堆栈溢出中尝试了一些解决方案,但不适合我的情况。当我试着 Android Camera Preview Stretched 解决方案,然后相机预览没有显示,所以我无法确定它是否解决了。

    请告诉我可以做些什么来获得这个问题的最佳解决方案?

    1 回复  |  直到 7 年前
        1
  •  0
  •   Abhay Koradiya    7 年前

    拍摄图像后需要裁剪位图。放

    public static void cropToJpeg2(final byte[] jpeg, final AspectRatio targetRatio, final int jpegCompression, final CameraUtils.BitmapCallback callback) {
    
    final Handler ui = new Handler();
    WorkerHandler.run(new Runnable() {
        @Override
        public void run() {
            Bitmap image = decodeBitmap(jpeg, Integer.MAX_VALUE, Integer.MAX_VALUE);
            Rect cropRect = computeCrop(image.getWidth(), image.getHeight(), targetRatio);
            final Bitmap crop = Bitmap.createBitmap(image, cropRect.left, cropRect.top, cropRect.width(), cropRect.height());
            image.recycle();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            crop.compress(Bitmap.CompressFormat.JPEG, jpegCompression, out);
    
            ui.post(new Runnable() {
                @Override
                public void run() {
                    callback.onBitmapReady(crop);
                }
            });
    
        }
    });
    }
    

    计算作物功能

    private static Rect computeCrop(int currentWidth, int currentHeight, AspectRatio targetRatio) {
        AspectRatio currentRatio = AspectRatio.of(currentWidth, currentHeight);
        logger.e("CropHelper", "computeCrop: currentRatio " + currentRatio);
        logger.e("CropHelper", "computeCrop: targetRatio " + targetRatio);
        int x, y, width, height;
        if (currentRatio.toFloat() > targetRatio.toFloat()) {
            height = currentHeight;
            width = (int) (height * targetRatio.toFloat());
            y = 0;
            x = (currentWidth - width) / 2;
        } else {
            width = currentWidth;
            height = (int) (width / targetRatio.toFloat());
    //            y = (currentHeight - height) / 2;
            y = 0;  //change above line for crop exact image from camera (remove heading).
            x = 0;
        }
        return new Rect(x, y, x + width, y + height);
    }
    

    检查 WorkerHandler class .

    注:- decodeBitmap 函数在Exif计算后返回位图以进行旋转。

    推荐文章