2017-10-20 199 views
9

我到目前为止已经试过的有效模糊:相机预览


转换每一帧转换成位图,与library模糊,并把它变成ImageView这是在摄像头预览的前面。显然太慢了 - 像1 fps


然后我开始使用的renderScript其模糊的每一帧和结果处理的应放置在TextureView其是盖相机预览。

的这种方法的代码本质撕成小块:

使用BlurFilter

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() 
    } 
} 

MainActivity

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 我是能够提高性能与模糊之前缩小输入日期。我推动这些更改来测试回购。即使在低端设备上,但具有低分辨率(例如HD),在FHD和UHD上的性能也不错((8-12 FPS)

+0

你试过分析应用程序? – Xiao

+0

你的意思是Android Studio的分析器? – Divers

+0

是否有一个特别的原因,你为什么要用''ImageFormat.NV_21'''来处理yuv'''byte'''而不直接从相机中获取预览帧?使用USAGE_IO_INPUT和ImageFormat.YUV_420_888可以将相机2预览帧直接用于yuv分配。你将不得不切换到本地rs,但它应该没问题,因为你有minApi 19.如果那是好的,那么我认为我有一个解决方案。 –

回答

6

我想你可以采取的最好的办法是用TextureView更换CameraView并把它作为一个摄像头预览,你可以很容易找到的例子如何做到这一点这里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

它可以让你着色器应用到视频观看,如此反复,就可以使用模糊着色器达到预期的效果。

例为这个图书馆:https://stackoverflow.com/a/38125734/3286059

编辑

所以我分叉从Nekocode一个伟大的图书馆,并增加了工作的模糊滤镜。 请看我最近的提交。 https://github.com/Dimezis/CameraFilter

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

如果你需要更快/更好/更简单的模糊着色器,你可以在https://www.shadertoy.com

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

+0

感谢您的回答。我之前看过所有这些链接。你有尝试过什么吗?因为第一个关于模糊静态图像,第二个关于模糊视频流。 – Divers

+0

@Divers我尝试了第一个,特别是这个例子https://github.com/nekocode/blur-using-textureview/blob/master/app/src/main/java/cn/nekocode/blurringview/sample/BlurFilter的.java。它实际上模糊不是一个静态图像,而是一个不断更新的视图层次结构(例如,滚动)。它的工作原理非常好,并且肯定会用相机流,就像第一个TextureView示例一样。其工作速度足够快的原因是,您不必每次都分配新的位图,而且在OpenGL着色器的后台线程中进行模糊处理,这本身就非常快。 – Dimezis

+0

@Divers谈到第二个库(VideoEffects)时,也可以使其呈现相机预览 - https://github.com/google/grafika/blob/master/src/com/android/grafika/CameraCaptureActivity.java – Dimezis

-3

你需要什么样的模糊?在运行时更改视频非常复杂的任务,以及使用简单的蒙版的最有效方式。只有面具,将适合我们的任务。即使是保存视频,我们也不仅应用转换,还会使用我们的蒙版录制视频帧。

对于您的情况,您可以将CameraView换成新面具,并带有蓝色动作。因此,您将包含像这样的布局。

< FrameLayout> 
    < /CameraView> 
    ...... 
< /FrameLayout> 

然后应用Blurred Mask进入FrameLayout视图。例如。设置背景,就像它显示In This Example

+0

它不起作用,就像那样。 – Divers