android - 相机预览的有效模糊

标签 android camera blur renderscript

到目前为止我尝试了什么:


将每一帧转换成位图,用library模糊它并将其放入相机预览前面的 ImageView 中。显然太慢了 - 大约 1 fps


然后我开始使用 RenderScript 来模糊每一帧,处理结果应该放在 TextureView 中,这是封面相机预览。

该方法的基本代码和平:

模糊滤镜

ScriptIntrinsicBlur.create(rs, Element.RGBA_8888(rs)).apply {
    setRadius(BLUR_RADIUS)
}
private val yuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(rs))
private var surface: SurfaceTexture? = null

private fun setupSurface() {
    if (surface != null) {
        aBlurOut?.surface = Surface(surface)
    }
}

fun reset(width: Int, height: Int) {
    aBlurOut?.destroy()

    this.width = width
    this.height = height

    val tbConvIn = Type.Builder(rs, Element.U8(rs))
            .setX(width)
            .setY(height)
            .setYuvFormat(android.graphics.ImageFormat.NV21)
    aConvIn = Allocation.createTyped(rs, tbConvIn.create(), Allocation.USAGE_SCRIPT)

    val tbConvOut = Type.Builder(rs, Element.RGBA_8888(rs))
            .setX(width)
            .setY(height)
    aConvOut = Allocation.createTyped(rs, tbConvOut.create(), Allocation.USAGE_SCRIPT)

    val tbBlurOut = Type.Builder(rs, Element.RGBA_8888(rs))
            .setX(width)
            .setY(height)
    aBlurOut = Allocation.createTyped(rs, tbBlurOut.create(),
            Allocation.USAGE_SCRIPT or Allocation.USAGE_IO_OUTPUT)

    setupSurface()
}

fun execute(yuv: ByteArray) {
    if (surface != null) {
        //YUV -> RGB
        aConvIn!!.copyFrom(yuv)
        yuvToRgb.setInput(aConvIn)
        yuvToRgb.forEach(aConvOut)
        //RGB -> BLURED RGB
        blurRc.setInput(aConvOut)
        blurRc.forEach(aBlurOut)
        aBlurOut!!.ioSend()
    }
}

主 Activity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    initQrScanner()
}

override fun onStart() {
    super.onStart()
    fotoapparat.start()
}

override fun onStop() {
    fotoapparat.stop()
    super.onStop()
}

private fun initQrScanner() {
    val filter = BlurFilter(RenderScript.create(this))
    tvWholeOverlay.surfaceTextureListener = filter

    fotoapparat = Fotoapparat
            .with(this)
            .into(cvQrScanner)
            .frameProcessor({
                if (it.size.width != filter.width || it.size.height != filter.height) {
                    filter.reset(it.size.width, it.size.height)
                }
                filter.execute(it.image)
            })
            .build()
}

activity_main.xml

<android.support.constraint.ConstraintLayout 
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"
    tools:context="com.blur.andrey.blurtest.MainActivity">

    <io.fotoapparat.view.CameraView
        android:id="@+id/cvQrScanner"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextureView
        android:id="@+id/tvWholeOverlay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

不幸的是它仍然很慢 - 3-4 FPS。模糊叠加层也会旋转,但这是另一个问题。


我创建了 test project on Github 您可以在其中快速重现问题并检查如何进行优化。期待您的想法。


UPD 我能够在模糊之前通过缩小输入日期来提高性能。我将这些更改推送到测试 repo 。现在即使在低端设备上我也有非常好的(15-20 FPS)性能,但分辨率低(例如高清),并且在 FHD 和 UHD 上不够好((8- 12 帧/秒)

最佳答案

我认为您可以采用的最佳方法是将 CameraView 替换为 TextureView 并将其用作相机预览。您可以在此处轻松找到如何操作的示例 https://developer.android.com/reference/android/view/TextureView.html , 和这里 https://github.com/dalinaum/TextureViewDemo/blob/master/src/kr/gdg/android/textureview/CameraActivity.java .

下一步是在您的 TextureView 上使用模糊着色器。你可以在这里找到一个例子: https://github.com/nekocode/blur-using-textureview/blob/master/app/src/main/java/cn/nekocode/blurringview/sample/BlurFilter.java

您可以使用此着色器或找到一些更漂亮的着色器。

如果你想要一个现成的解决方案,你可以看看这个库: https://github.com/krazykira/VidEffects

它允许您将着色器应用于视频 View ,因此您可以再次使用模糊着色器来实现所需的效果。

此库的示例:https://stackoverflow.com/a/38125734/3286059

编辑

所以我从 Nekocode fork 了一个很棒的库并添加了一个有效的模糊过滤器。 请查看我的最新提交。 https://github.com/Dimezis/CameraFilter

正如我所说,TextureView + GL 着色器。要启用模糊着色器,请单击右上角的菜单并选择相应的选项。

如果您需要更快/更好/更简单的模糊着色器,您可以在 https://www.shadertoy.com 上搜索一个

在某些设备上,您可能会翻转相机预览,但这是另一个需要解决的问题。

关于android - 相机预览的有效模糊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46851700/

相关文章:

android - 将多个 Flash 动画导出为 Android APK

java - 我可以使用TextureView同时显示相机预览和检测到的线吗?

ios - 捕获有边界的图像?

ios - 用Qt获得类似iOS7的模糊效果

背景图像上的 CSS 模糊,但内容上没有

ios - 如何在 iOS 上实现方框或高斯模糊

android - 在一个应用程序 Activity 中放置两个广告是否违反 admob 规则?

android - 如何解决任务 ':app:kaptDebugKotlin'的配置错误?

android - 将 LinearLayout 内的按钮高度与水平方向相匹配

android - 在 map View 上平滑地动画化相机路径