到目前为止我已尝试过:
将每个帧转换为位图,使用test project on Github将其模糊,并将其放入相机预览前面的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 。旋转模糊叠加也是一种旋转,但这是另一个问题。
我已经创建了 {{3}} ,您可以快速重现问题并检查如何进行优化。期待您的想法。
UPD 我可以通过在模糊之前缩小输入日期来提高性能。我将这些更改推送到测试回购。现在即使在低端设备上我也有非常好的(15-20 FPS)性能,但是具有低分辨率(例如HD),并且在FHD和UHD上不够好((8- 12 FPS)。
答案 0 :(得分:8)
我认为您可以采取的最佳方法是将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
它允许您将着色器应用于视频视图,因此您可以再次使用模糊着色器来获得所需的效果。
此库的示例:https://stackoverflow.com/a/38125734/3286059
修改强>
所以我从Nekocode分叉了一个很棒的库,并添加了一个工作模糊过滤器。 请看我最近的提交。 https://github.com/Dimezis/CameraFilter
正如我所说,TextureView + GL着色器。要启用模糊着色器,请单击右上角的菜单,然后选择相应的选项。
如果您需要更快/更好/更简单的模糊着色器,可以在https://www.shadertoy.com
上搜索一个在某些设备上,您可能会翻转相机预览,但这是另一个需要解决的问题。
答案 1 :(得分:1)
我使用 RenderScript 实现了不错的实时相机模糊效果,并将输出结果预览到 ImageView。
首先我创建了一个使用渲染脚本的 BlurBuilder 类
public class BlurBuilder {
private static final float BITMAP_SCALE = 4f;
private static final float BLUR_RADIUS = 25f; // 0 - 25
public static Bitmap blur(Context context, Bitmap image) {
int width = Math.round(image.getWidth() * BITMAP_SCALE);
int height = Math.round(image.getHeight() * BITMAP_SCALE);
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
RenderScript rs = RenderScript.create(context);
ScriptIntrinsicBlur intrinsicBlur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
intrinsicBlur.setRadius(BLUR_RADIUS);
intrinsicBlur.setInput(tmpIn);
intrinsicBlur.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}}
我使用 TextureView 来预览相机预览
在 TextureView 上添加一个 ImageView
添加一个 setSurfaceTextureListener 并且我添加了一些调整
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
Bitmap bm = BlurBuilder.blur(getApplicationContext(),textureView.getBitmap());
imageView.setImageBitmap(bm);
}
PS:我在 TextureView 中使用了 Opengles。
我的结果:https://vimeo.com/517761912 设备名称:三星 j7 prime 操作系统版本:Android 8.1 相机:13mp 30fps(设备容量)
答案 2 :(得分:-4)
你需要什么样的模糊?在运行时更改视频非常复杂的任务,并且最有效的方式是使用简单的Mask。只有面具,将适合我们的任务。即使是为了保存视频,我们不仅应用转换,还使用我们的Mask录制视频帧。
在您的情况下,您可以使用Blue操作将CameraView
包装到新的Mask中。因此,您将包含此处的布局。
< FrameLayout>
< /CameraView>
......
< /FrameLayout>
然后将模糊蒙版应用于FrameLayout
视图。对于前者设置背景,就像它显示In This Example