我正在使用 CameraX 库构建布局的相机预览,我想模糊预览。我搜索了很多方法,但大多数都过时或太复杂。
现在我尝试参考CameraX:如何设置PreviewView的背景?中的模糊方法,但我的相机预览仍然不模糊。
我尝试将相机预览捕获为纹理视图并将其转换为位图,然后使用渲染脚本对其进行模糊处理。但是,我的日志一直显示“相机预览位图为空”。
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_welcome)
cameraPreview = findViewById(R.id.cameraPreview);
cameraBtn = findViewById(R.id.cameraButton);
blurOverlayImageView = findViewById(R.id.blurOverlay);
// Request camera permission and initialize CameraX
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.CAMERA), CAMERA_PERM_CODE
)
}
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture?.addListener({
val cameraProvider = cameraProviderFuture?.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
cameraBtn.setOnClickListener {
val intent = Intent(this, CameraActivity::class.java)
startActivity(intent)
}
}
private fun bindPreview(cameraProvider: ProcessCameraProvider?) {
// Configure the preview use case
val preview = Preview.Builder().build()
val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
// Connect the preview to the PreviewView
preview.setSurfaceProvider(cameraPreview.surfaceProvider)
// Unbind any previous use cases before rebinding
try {
cameraProvider?.unbindAll()
// Bind the camera use cases to the cameraProvider
val camera = cameraProvider?.bindToLifecycle(this, cameraSelector, preview)
} catch (exc: Exception) {
// Handle exceptions here
}
}
private fun allPermissionsGranted() = ActivityCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
private fun startCamera() {
val cameraProvider = cameraProviderFuture?.get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
// Initialize the preview animator for continuous blur
initializePreviewAnimator()
val preview = Preview.Builder()
.build()
.also { it.setSurfaceProvider(cameraPreview.surfaceProvider) }
try {
cameraProvider?.unbindAll()
val camera = cameraProvider?.bindToLifecycle(
this, cameraSelector, preview
)
} catch (exc: Exception) {
// Handle exceptions here
}
}
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == CAMERA_PERM_CODE) {
if (allPermissionsGranted()) {
startCamera()
} else {
Toast.makeText(this, "Camera Permission is Required to Use the camera.", Toast.LENGTH_SHORT).show()
}
}
}
private fun blurRenderScript(smallBitmap: Bitmap, radius: Int): Bitmap? {
val defaultBitmapScale = 0.1f
val width = (smallBitmap.width * defaultBitmapScale).roundToInt()
val height = (smallBitmap.height * defaultBitmapScale).roundToInt()
val inputBitmap = Bitmap.createScaledBitmap(smallBitmap, width, height, false)
val outputBitmap = Bitmap.createBitmap(inputBitmap)
val renderScript = RenderScript.create(this)
val theIntrinsic = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
val tmpIn = Allocation.createFromBitmap(renderScript, inputBitmap)
val tmpOut = Allocation.createFromBitmap(renderScript, outputBitmap)
theIntrinsic.setRadius(radius.toFloat())
theIntrinsic.setInput(tmpIn)
theIntrinsic.forEach(tmpOut)
tmpOut.copyTo(outputBitmap)
return outputBitmap
}
private fun initializePreviewAnimator() {
// Initializing the preview animator with values to blur
previewAnimator = ValueAnimator.ofInt(6, 12, 18, 24, 25)
// Set the animation to repeat infinitely
previewAnimator.repeatCount = ValueAnimator.INFINITE
previewAnimator.repeatMode = ValueAnimator.RESTART
// Setting animation duration for each frame (adjust as needed)
//previewAnimator.duration = 100 // Set the duration for each frame (in milliseconds)
// Adding listener for every value update of the animation
previewAnimator.addUpdateListener { animator ->
// Get the current blur level from the animator
val blurLevel = animator.animatedValue as Int
// Capture the camera preview frame
val cameraBitmap = captureCameraPreview()
if (cameraBitmap != null) {
// Blurring the captured frame using the blurRenderScript function
val blurredBitmap = blurRenderScript(cameraBitmap, blurLevel)
// Set the blurred bitmap as the ImageView's image
blurOverlayImageView.setImageBitmap(blurredBitmap)
} else {
Log.e(TAG, "Camera preview bitmap is null")
}
}
// Start the previewAnimator when you start the camera
previewAnimator.start()
}
private fun captureCameraPreview(): Bitmap? {
val view = cameraPreview.getChildAt(0) as? TextureView
return view?.bitmap
}
使用 CameraX 应用效果的推荐方法是 CameraEffect API。您需要为此编写 OpenGL 代码。您可以在此处查看代码示例。
在该示例代码中,OpenGlRenderer 包含 OpenGL 代码。复制此代码时,更新片段着色器以应用模糊效果。模糊着色器的示例可以在这个答案中找到。或者,您可以要求 ChatGPT 更新具有模糊效果的示例代码。