【问题标题】:Custom Square camera, so close but camera preview is wrong自定义方形相机,如此接近但相机预览错误
【发布时间】:2016-07-28 14:10:12
【问题描述】:

我正在做一个需要制作自定义方形相机的项目。我现在正在做一个示例项目,我会上传代码。

游戏计划是打开一个相机预览。在顶部绘制视图以产生它是方形相机的错觉。拍摄全屏图片,最后裁剪图片。

一切似乎都在按计划进行,但是当我最终拍摄照片时,保存在手机中的全屏照片的结果与我拍摄的照片不同。让我举例说明预期结果和最终结果,以向您展示问题所在:

如您所见,当我查看画廊中保存的图片时,我可以看到左侧的桌子以及右侧的部分墙壁,这些部分在我拍照时不在我的相机预览中。

我在我的相机预览类中尝试了各种不同的东西,但目前我正在使用在这篇文章的答案之一中找到的相机预览类:Android Camera Preview Stretched

我目前只发布我的相机预览课程,但如果您需要我的 main/xml 等,我会更愿意将其发布。我觉得我已经搜索了很长时间,但我无法弄清楚发生了什么。谢谢!

公共类 CameraPreview 扩展 SurfaceView 实现 SurfaceHolder.Callback {

private static final String TAG = "CameraPreview";

private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;

public CameraPreview(Context context, Camera camera) {
    super(context);
    mContext = context;
    mCamera = camera;

    // supported preview sizes
    mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
    for(Camera.Size str: mSupportedPreviewSizes)
        Log.e(TAG, str.width + "/" + str.height);

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    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) {
    // empty. surfaceChanged will take care of stuff
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + 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
    // start preview with new settings
    try {

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        mCamera.setParameters(parameters);
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }

    float ratio;
    if(mPreviewSize.height >= mPreviewSize.width)
        ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
    else
        ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

//      One of these methods should be used, second method squishes preview slightly
        setMeasuredDimension(width, (int) (width * ratio));
//      setMeasuredDimension((int) (width * ratio), height);

    float camHeight = (int) (width * ratio);
    float newCamHeight;
    float newHeightRatio;

    if (camHeight < height) {
        newHeightRatio = (float) height / (float) mPreviewSize.height;
        newCamHeight = (newHeightRatio * camHeight);
        Log.e(TAG, camHeight + " " + height + " " + mPreviewSize.height + " " + newHeightRatio + " " + newCamHeight);
        setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight);
        Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | H_ratio - " + newHeightRatio + " | A_width - " + (width * newHeightRatio) + " | A_height - " + newCamHeight);
    } else {
        newCamHeight = camHeight;
        setMeasuredDimension(width, (int) newCamHeight);
        Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | A_width - " + (width) + " | A_height - " + newCamHeight);
    }
}

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;

    if (sizes == null)
        return null;

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

    int targetHeight = h;

    for (Camera.Size size : sizes) {
        double ratio = (double) size.height / size.width;
        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;
}

}

【问题讨论】:

    标签: android camera


    【解决方案1】:

    class Preview extends ViewGroup implements SurfaceHolder.Callback {
        private final String TAG = "Preview";
    
        SurfaceView mSurfaceView;
        SurfaceHolder mHolder;
        Size mPreviewSize;
        List<Size> mSupportedPreviewSizes;
        Camera mCamera;
        Context context;
        boolean surfaceExists = false;
        boolean isPreview = false;
        static int wid = 0;
        static int hig = 0;
        
    
        int y = 0;
        private static final double ASPECT_RATIO = 3.0 / 4.0;
        private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
        private static final int PREVIEW_SIZE_MAX_WIDTH = 3264;
        Preview(Context context, SurfaceView sv) {
            super(context);
            this.context=context;
            mSurfaceView = sv;
    		mHolder = mSurfaceView.getHolder();
            mHolder.addCallback(this);
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
    
      @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            
        	int height = MeasureSpec.getSize(heightMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);
    
            if (width > height * ASPECT_RATIO) {
                 width = (int) (height * ASPECT_RATIO + .5);
            } else {
                height = (int) (width / ASPECT_RATIO + .5);
            }
    
            setMeasuredDimension(width, height);
        }
    public void determineDisplayOrientation(Camera camera) {
            CameraInfo cameraInfo = new CameraInfo();
            Camera.getCameraInfo(0, cameraInfo);
    
            Display display = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
            int rotation = display.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 displayOrientation;
    
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                displayOrientation = (cameraInfo.orientation + degrees) % 360;
                displayOrientation = (360 - displayOrientation) % 360;
            } else {
                displayOrientation = (cameraInfo.orientation - degrees + 360) % 360;
            }
    
            camera.setDisplayOrientation(displayOrientation);
    
        }
        @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;
                    child.layout((width - scaledChildWidth) / 2, 0,
                            (width + scaledChildWidth) / 2, height);
                } else {
                    final int scaledChildHeight = previewHeight * width / previewWidth;
                    child.layout(0, (height - scaledChildHeight) / 2,
                            width, (height + scaledChildHeight) / 2);
                }
            }
        }
    
        public void surfaceCreated(SurfaceHolder holder) {
            // The Surface has been created, acquire the camera and tell it where
            // to draw.
            try {
                if (mCamera != null) {
                	
                    mCamera.setPreviewDisplay(holder);
                }
            } catch (IOException exception) {
                Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
            }
        }
    
        public void surfaceDestroyed(SurfaceHolder holder) {
            // Surface will be destroyed when we return, so stop the preview.
        	try {
      		  if (mCamera != null) {
      	        	mHolder.removeCallback(this);
      	            mCamera.stopPreview();
      	            mCamera.release();
      	        }
    		} catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
        }
     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; 
        }
    
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        	
        	wid = w;
        	hig = h;
        	
        	
        }
         private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters){
            Camera.Size bestSize = null;
            List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();
            
            bestSize = sizeList.get(0);
            
            for(int i = 1; i < sizeList.size(); i++){
             if((sizeList.get(i).width * sizeList.get(i).height) >
               (bestSize.width * bestSize.height)){
              bestSize = sizeList.get(i);
             }
            }
    
            return bestSize;
           }
        
        public void setupCamera(Camera camera,boolean isResolutionHigh) {
     	   mCamera = camera;
        	if (mCamera != null) {
        		determineDisplayOrientation(mCamera); 
        	   Camera.Parameters myParameters = mCamera.getParameters();
        		
        		if(isResolutionHigh){
        	   
          	    Camera.Size myBestSize = getBestPreviewSize(wid, hig, myParameters);
          	   
          	   if(myBestSize != null){
          	    myParameters.setPreviewSize(myBestSize.width, myBestSize.height);
          	    mCamera.setParameters(myParameters);
          	    mCamera.startPreview();
          	    isPreview = true;
          	    
          	   
          	      }
          	   
        		}
        		
        		else{
        			
        			 Size bestPreviewSize = determineBestPreviewSize(myParameters);
        		       Size bestPictureSize = determineBestPictureSize(myParameters);
    
        		       myParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
        		       myParameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
        		       myParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
    
        		       mCamera.setParameters(myParameters);
        		}
        	}
        }
        private Size determineBestPreviewSize(Camera.Parameters parameters) {
           List<Size> sizes = parameters.getSupportedPreviewSizes();
    
           return determineBestSize(sizes, PREVIEW_SIZE_MAX_WIDTH);
       }
    
       private Size determineBestPictureSize(Camera.Parameters parameters) {
           List<Size> sizes = parameters.getSupportedPictureSizes();
    
           return determineBestSize(sizes, PICTURE_SIZE_MAX_WIDTH);
       }
    
       protected Size determineBestSize(List<Size> sizes, int widthThreshold) {
           Size bestSize = null;
    
           for (Size currentSize : sizes) {
               boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
               boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
               boolean isInBounds = currentSize.width <= PICTURE_SIZE_MAX_WIDTH;
    
               if (isDesiredRatio && isInBounds && isBetterSize) {
                   bestSize = currentSize;
               }
           }
    
           if (bestSize == null) {
              // listener.onCameraError();
    
               return sizes.get(0);
           }
    
           return bestSize;
       }
       }
       }

    试试看

    【讨论】:

    • 谢谢,我试过了,但我仍然遇到同样的问题?你能解决这个问题吗?我也在不同的设备上试过
    • 以上代码适用于所有设备...除了三星 S5
    • 所以我用方形相机解决了我的裁剪图像问题
    猜你喜欢
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多