CameraX 实现摄像头旋转预览
问题
最近接到一个需求需要链接一台电子秤的2个usb摄像头,遇到了2个问题:一个是usb摄像头的链接访问,另一个是摄像头默认被旋转了90。下面记录下解决方案。
解决方案
usb链接问题
原有项目使用的是CameraX实现摄像头预览和图片抓取,所以这里也是用CameraX来实现usb摄像头链接。
- 布局文件layout.xml
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:scaleType="fillCenter"/>
- 预览页面LayoutActivity.kt
/**
* 开始预览摄像头
*/
fun startCamera() {
// 相机预览功能
val preview = Preview.Builder()
.build()
.also { it.setSurfaceProvider(previewView.surfaceProvider) }
// 捕获静态图像
imageCapture = ImageCapture
.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9) //修改图片捕获尺寸为16:9和当前屏幕保持一致
.setJpegQuality(60)
.build()
//
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
cameraProvider.unbindAll() // 解绑所有已绑定的用例(避免重复绑定)
cameraProvider.bindToLifecycle(
// 绑定摄像头生命周期:将预览用例绑定到当前 Activity 的生命周期
this as LifecycleOwner,
getCameraSelector(this, 102, CameraSelector.LENS_FACING_FRONT),
preview,
imageCapture,
)
}, ContextCompat.getMainExecutor(this))
}
/**
* 相机选择器
* @param context 用于获取 cameraManager
* @param cameraId 当 lensFacing 失效时通过 cameraId 来指定相机
* @param lensFacing 指定前置还是后置摄像头
*/
fun getCameraSelector(context: Context, cameraId: Int, lensFacing: Int): CameraSelector? {
// 相机选择器
val cameraSelector = CameraSelector.Builder()
// 判断是否有默认的相机
val cameraProvider = ProcessCameraProvider.getInstance(context).get()
val backCamera = cameraProvider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)
val frontCamera = cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
// 默认的前置和后置相机都没有,需要通过指定cameraId来获取;
// cameraId可通过cameraManager.cameraIdList获取,具体是哪个id需要自己测试。
if (!frontCamera && !frontCamera) {
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
if (cameraManager.cameraIdList.isEmpty()) {
return null
}
// for (id in cameraManager.cameraIdList) {
// Log.i(TAG, "camera id:${id}")
// val characteristics = cameraManager.getCameraCharacteristics(id) // 获取摄像头特性
// val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
// Log.i("TAG", "lensFacing:${cameraLensFacing == CameraMetadata.LENS_FACING_FRONT}") // 摄像头方向
// val sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)
// Log.i(TAG, "orientation: $sensorOrientation") // 摄像头旋转角度
// }
cameraSelector.addCameraFilter(DeviceCameraFilter("$cameraId"))
} else {
cameraSelector.requireLensFacing(lensFacing)
}
return cameraSelector.build()
}
摄像头被旋转了90度
这个问题花了我不少时间来解决,通过AI查询给出的答案是通过 Preview#setTargetRotation() 来实现,但是我设置之后却没有效果。我尝试设置 PreviewView 的 rotation ,结果只有视图组建发生了旋转,相机的图片依然没有发生改变。最后通过外网搜索stackoverflow终于找到了答案:其实还是通过 Preview#setTargetRotation() 来实现,只过不需将 PreviewView#implementationMode 设置成 PreviewView.ImplementationMode.COMPATIBLE,原因在CameraX官网给出了说明。
fun startCamera(){
// 必要设置,否则摄像头旋转无效
previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE
val preview = Preview.Builder()
.setTargetRotation(Surface.ROTATION_270) // 旋转相机
.build()
.also { it.setSurfaceProvider(previewView.surfaceProvider) }
// 其他代码
}
对于usb摄像头的链接访问
usb摄像头、特别是一些双目摄像头使用CameraX访问会出现展示成黑白的情况,推荐使用开源项目UVCCamera。

浙公网安备 33010602011771号