Более оптимизированная для памяти версия Bitmap.createScaledBitmap? - PullRequest
0 голосов
/ 10 июля 2019

Я полностью понимаю, что "преждевременная оптимизация - корень всего зла. " Однако я дошел до того, что считаю, что оптимизация, которую я хочу сделать, больше не может считаться "преждевременной" .

Я пишу приложение для Android, которое, помимо прочего, передает поток живого изображения с USB-устройства, выполняет некоторую обработку изображения с помощью OpenCV, преобразует кадр в растровое изображение, а затем отображает это растровое изображение в SurfaceView в реальном времени. время.

У меня все работает, (прямая трансляция корректно отображается в SurfaceView), и инструмент «Профилировщик» в Android Studio показывает, что я хорошо справился с управлением памятью (обратите внимание, что сборщик мусора не запускается один раз в 10 секунд, показанные ниже ):

enter image description here

Однако, поскольку изображение, которое я передаю, имеет низкое разрешение (320x180), когда я рендерим его непосредственно в SurfaceView, оно фактически оказывается довольно маленьким на экране устройства.

Таким образом, я решил масштабировать растровое изображение до максимального размера, который поместился бы в SurfaceView, перед его отображением на экране. Однако после этого я с ужасом обнаружил, что график использования памяти теперь выглядит ужасно! (Сборщик мусора работает чаще, чем раз в секунду! )

enter image description here

Вот соответствующие фрагменты кода:

  • Перед масштабированием растрового изображения (график чистой памяти):

    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() является виновником. Кто-нибудь знает другой способ сделать то же самое, что не дает сборщику мусора за свои деньги?

1 Ответ

0 голосов
/ 10 июля 2019

Вместо того, чтобы масштабировать само растровое изображение, как вы делаете - вы не можете масштабировать во время рисования?

Я смотрю на canvas.drawBitmap (Растровое изображение, Rect src,Rect dst, Paint paint) - обратите внимание, что он принимает как исходные, так и целевые прямоугольники.

Вам нужно установить источник для ваших (маленьких) размеров изображения, а dest для размеров вашей поверхности.

...