You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义相机拍照:如何仅保留界面圆形显示区域的图像?

嘿,这个问题我之前做自定义相机的时候也踩过坑!你界面上的圆形覆盖层只是视觉上的遮罩,相机本身还是会拍摄完整的传感器区域,所以得额外处理才能拿到你要的圆形区域图像。下面给你两种实用的方案,按需选就行:

方案一:拍照后裁剪(兼容性拉满,新手友好)

这是最稳妥的方式,不管你用的是旧的Camera API还是新的Camera2,都能搞定。核心思路是:先拿到相机拍的完整图像,再把它裁剪成和你界面上圆形区域对应的部分。

具体步骤:

  1. 建立预览与拍照图像的坐标映射
    相机预览的尺寸(比如1920×1080)和最终拍照的图像尺寸(比如4032×3024)比例大概率不一样,而且竖屏拍照时图像还会旋转,所以得先把你界面上圆形遮罩的坐标,转换成拍照图像上的对应位置:

    • 先获取你相机预览View(SurfaceView/TextureView)的实际宽高,还有圆形遮罩相对于这个View的left、top、宽高
    • 计算缩放比例:x缩放比 = 拍照图像宽度 / 预览View宽度,y缩放比 = 拍照图像高度 / 预览View高度
    • 如果是竖屏,记得先把拍照图像旋转到正确方向,再用上面的比例计算坐标
  2. 对Bitmap进行圆形裁剪
    把拍照得到的图像转成Bitmap后,用Canvas和Path来裁剪出圆形区域,代码示例:

// 假设originalBitmap是拍照得到的原始图像Bitmap
// circleLeft、circleTop是圆形遮罩在预览View上的左上角坐标,circleWidth是遮罩直径
float scaleX = (float) originalBitmap.getWidth() / previewView.getWidth();
float scaleY = (float) originalBitmap.getHeight() / previewView.getHeight();

// 计算原始图像中对应圆形区域的矩形
RectF srcRect = new RectF(
    circleLeft * scaleX,
    circleTop * scaleY,
    (circleLeft + circleWidth) * scaleX,
    (circleTop + circleWidth) * scaleY
);

// 创建和圆形遮罩等大的空白Bitmap
Bitmap croppedBitmap = Bitmap.createBitmap(circleWidth, circleWidth, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(croppedBitmap);

// 绘制圆形裁剪路径
Path circlePath = new Path();
circlePath.addCircle(circleWidth/2f, circleWidth/2f, circleWidth/2f, Path.Direction.CW);
canvas.clipPath(circlePath);

// 把原始图像的对应区域画到新Bitmap上
canvas.drawBitmap(originalBitmap, srcRect, new RectF(0, 0, circleWidth, circleWidth), null);

// 现在croppedBitmap就是你要的圆形图像了
方案二:用Camera2 API直接指定拍照区域(高效进阶)

如果你的App只需要兼容Android 5.0(API 21)及以上,那可以用Camera2 API让相机硬件直接拍摄你要的区域,省去后期裁剪的步骤,性能更好。

关键是在创建拍照请求时,设置SCALER_CROP_REGION参数,指定传感器上的裁剪区域:

// 先通过CameraCharacteristics获取传感器的有效尺寸
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
Rect sensorActiveSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

// 把你界面上的圆形区域转换成传感器坐标系统的矩形(这里需要处理方向和比例转换,具体逻辑根据你的布局调整)
Rect cropRect = calculateSensorCropRect(circleArea, sensorActiveSize, previewSize, displayRotation);

// 创建拍照请求
CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 设置裁剪区域
captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRect);
// 其他必要设置:自动对焦、闪光灯、输出目标等
// ...

// 发送拍照请求
cameraCaptureSession.capture(captureBuilder.build(), captureCallback, null);

这里的calculateSensorCropRect需要你自己实现,核心是把界面上的坐标转换为相机传感器的横屏坐标,还要保证裁剪区域的比例和拍照输出的图像比例一致,不然相机可能会自动调整。

几个必踩的坑提醒
  • 图像方向问题:竖屏拍照时,相机输出的图像通常是横的,一定要先旋转到正确方向再处理,不然裁剪出来的区域会歪
  • 内存溢出:如果拍照图像尺寸很大,直接转Bitmap可能会OOM,建议用BitmapFactory.Options.inSampleSize先缩小图像再裁剪
  • 遮罩与实际区域对齐:测试时可以给遮罩加个边框,对比裁剪后的图像,确保坐标转换没有错误

内容的提问来源于stack exchange,提问作者Achy97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:21:51