Home > Back-end >  Android: improving conversion speed of grayscale bitmap to monochromatic
Android: improving conversion speed of grayscale bitmap to monochromatic

Time:12-12

How can I improve the speed of the following process of conversion?

For grayscale bitmap of 384x524 pixels, this takes around 2,1 seconds on the target device.

fun convertToMonochromatic(bitmap: Bitmap): Bitmap {
    val result = Bitmap.createBitmap(bitmap.width, bitmap.height, bitmap.config)

    for (row in 0 until bitmap.height) {
        for (col in 0 until bitmap.width) {
            val hsv = FloatArray(3)
            Color.colorToHSV(bitmap.getPixel(col, row), hsv)

            if (hsv[2] > 0.7f) {
                result.setPixel(col, row, Color.WHITE)
            } else {
                result.setPixel(col, row, Color.BLACK)
            }
        }
    }

    return result
}

Is there some "mass operation", transforming all the pixels at once directly based on the HSV and the Value particulary

CodePudding user response:

I am pretty sure there are libraries out there that provide fast bitmap operations. Considering your bitmap contains 201 216 pixels, your main problem is not the number of iterations but the speed of each iteration instead. However, you can use getPixels and setPixels methods to avoid frequent method switching and set all pixels at once, moreover you can optimize memory usage and store pixels in array, accessing indices of which will be slightly faster than accessing specific pixels of a Bitmap object. You also won't need an unfinished bitmap object till your array will be filled.

Array memory access is optimized due to caching of following memory chunks (computer predicts, that there will be accessing of several array elements, therefore it can cache the array data, since it is sequentional in memory). Bitmap is also associated with an array, however it is an object, so accessing its fields too frequently can be a bit slow.

val width = bitmap.width
val height = bitmap.height
val length = width * height
val pixelsArr = IntArray(length)

bitmap.getPixels(pixelsArr, 0, width, 0, 0, width, height)

for (i in 0 until length) {
    val hsv = FloatArray(3)
    Color.colorToHSV(pixelsArr[i], hsv)
    
    if (hsv[2] > 0.7f) {
        pixelsArr[i] = Color.rgb(255, 255, 255)
    } else {
        pixelsArr[i] = Color.rgb(0, 0, 0)
    }
}

val result = Bitmap.createBitmap(width, height, bitmap.config)
result.setPixels(pixels, 0, width, 0, 0, width, height)

CodePudding user response:

Using this access, to iterate the pixels one by one, it seems the main time consuming part is the colorToHSV function. It computes more info, than the needed Value.

Description of the transform https://www.rapidtables.com/convert/color/rgb-to-hsv.html

After the following adjustion, the needed time for the given size, is reduced from 2,1 seconds to 0,1 second.

    fun convertToMonochromatic(bitmap: Bitmap): Bitmap {
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, bitmap.config)

        val size = bitmap.width * bitmap.height
        val input = IntArray(size)
        val output = IntArray(size)

        bitmap.getPixels(input, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)

        var current = 0
        input.forEach {

            val red = it shr 16 and 0xFF
            val green = it shr 8 and 0xFF
            val blue = it and 0xFF

            val max = maxOf(red, green, blue)
            if (max > 175) {
                output[current  ] = Color.WHITE
            } else {
                output[current  ] = Color.BLACK
            }
        }

        result.setPixels(output, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)

        return result
    }
  • Related