Bitmap.createScaledBitmap 的更多内存优化版本?
More memory-optimised version of Bitmap.createScaledBitmap?
我完全理解 "premature optimization is the root of all evil." 但是,我已经到了一个地步,我认为我想做的优化不能再考虑 "premature".
我正在编写一个 Android 应用程序,其中包括从 USB 设备流式传输实时图像提要,使用 OpenCV 执行一些图像处理,将帧转换为位图,然后渲染它实时位图到 SurfaceView。
我的一切正常,(实时提要正确呈现到 SurfaceView)并且 Android Studio 的 "Profiler" 工具表明我已经很好地完成了内存管理(请注意垃圾收集器不会在下面显示的 10 秒内 运行 一次):
但是,因为我流式传输的图像分辨率较低 (320x180),当我将它直接渲染到 SurfaceView 时,它实际上最终在设备屏幕上非常小。
因此,我决定在将位图渲染到屏幕之前将位图缩放到适合 SurfaceView 的最大尺寸。然而,在这样做之后,我惊恐地发现内存使用图现在看起来很可怕! (垃圾收集器每秒 运行s 不止一次!)
以下是相关的代码片段:
缩放位图之前(清理内存图):
canvas = getHolder().lockCanvas();
openCvMat = frameQueue.take();
Utils.matToBitmap(openCvMat, bitmapFromMat);
mat.release();
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bitmapFromMat, 0, 0, null);
getHolder().unlockCanvasAndPost(canvas);
缩放位图后(可怕的内存图):
canvas = getHolder().lockCanvas();
openCvMat = frameQueue.take();
Utils.matToBitmap(openCvMat, bitmapFromMat);
mat.release();
canvas.drawColor(Color.BLACK);
Bitmap scaled = scaleBitmapToViewport(bitmapFromMat);
canvas.drawBitmap(scaled, 0, 0, null);
scaled.recycle();
getHolder().unlockCanvasAndPost(canvas);
scaleBitmapToViewport()
方法:
private Bitmap scaleBitmapToViewport(Bitmap bitmap)
{
//Landscape
if((canvas.getHeight() * aspectRatio) < canvas.getWidth())
{
return Bitmap.createScaledBitmap(bitmap, (int) Math.round(canvas.getHeight() * aspectRatio), canvas.getHeight(), true);
}
else //Portrait
{
return Bitmap.createScaledBitmap(bitmap, canvas.getWidth(), (int) Math.round(canvas.getWidth() / aspectRatio), true);
}
}
所以看起来 Bitmap.createScaledBitmap()
是罪魁祸首。有谁知道另一种方法来完成同样的事情,而不是给垃圾收集器一个 运行 的钱?
而不是像你正在做的那样缩放位图本身 - 你不能在绘图时缩放吗?
我正在查看 canvas.drawBitmap(Bitmap 位图、Rect src、Rect dst、Paint paint)- 请注意,它包含源矩形和目标矩形。
您需要将源设置为您的(小)图像尺寸,将目标设置为表面尺寸。
我完全理解 "premature optimization is the root of all evil." 但是,我已经到了一个地步,我认为我想做的优化不能再考虑 "premature".
我正在编写一个 Android 应用程序,其中包括从 USB 设备流式传输实时图像提要,使用 OpenCV 执行一些图像处理,将帧转换为位图,然后渲染它实时位图到 SurfaceView。
我的一切正常,(实时提要正确呈现到 SurfaceView)并且 Android Studio 的 "Profiler" 工具表明我已经很好地完成了内存管理(请注意垃圾收集器不会在下面显示的 10 秒内 运行 一次):
但是,因为我流式传输的图像分辨率较低 (320x180),当我将它直接渲染到 SurfaceView 时,它实际上最终在设备屏幕上非常小。
因此,我决定在将位图渲染到屏幕之前将位图缩放到适合 SurfaceView 的最大尺寸。然而,在这样做之后,我惊恐地发现内存使用图现在看起来很可怕! (垃圾收集器每秒 运行s 不止一次!)
以下是相关的代码片段:
缩放位图之前(清理内存图):
canvas = getHolder().lockCanvas(); openCvMat = frameQueue.take(); Utils.matToBitmap(openCvMat, bitmapFromMat); mat.release(); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bitmapFromMat, 0, 0, null); getHolder().unlockCanvasAndPost(canvas);
缩放位图后(可怕的内存图):
canvas = getHolder().lockCanvas(); openCvMat = frameQueue.take(); Utils.matToBitmap(openCvMat, bitmapFromMat); mat.release(); canvas.drawColor(Color.BLACK); Bitmap scaled = scaleBitmapToViewport(bitmapFromMat); canvas.drawBitmap(scaled, 0, 0, null); scaled.recycle(); getHolder().unlockCanvasAndPost(canvas);
scaleBitmapToViewport()
方法:private Bitmap scaleBitmapToViewport(Bitmap bitmap) { //Landscape if((canvas.getHeight() * aspectRatio) < canvas.getWidth()) { return Bitmap.createScaledBitmap(bitmap, (int) Math.round(canvas.getHeight() * aspectRatio), canvas.getHeight(), true); } else //Portrait { return Bitmap.createScaledBitmap(bitmap, canvas.getWidth(), (int) Math.round(canvas.getWidth() / aspectRatio), true); } }
所以看起来 Bitmap.createScaledBitmap()
是罪魁祸首。有谁知道另一种方法来完成同样的事情,而不是给垃圾收集器一个 运行 的钱?
而不是像你正在做的那样缩放位图本身 - 你不能在绘图时缩放吗?
我正在查看 canvas.drawBitmap(Bitmap 位图、Rect src、Rect dst、Paint paint)- 请注意,它包含源矩形和目标矩形。
您需要将源设置为您的(小)图像尺寸,将目标设置为表面尺寸。