kotlin Android:提高灰度位图到单色的转换速度

9bfwbjaz  于 2022-12-13  发布在  Kotlin
关注(0)|答案(2)|浏览(204)

如何提高以下转换过程的速度?
对于384x524像素的灰度位图,在目标设备上此操作大约需要2.1秒。

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
}

是否有一些“批量操作”,直接根据HSV和值一次转换所有像素

zujrkrfu

zujrkrfu1#

我很肯定有一些库可以提供快速的位图操作。考虑到您的位图包含201 216个像素,您的主要问题不是迭代次数而是每次迭代的速度。但是,您可以使用getPixelssetPixels方法来避免频繁的方法切换,并一次性设置所有像素。此外,您可以优化内存使用,并将像素存储在数组中,访问数组的索引将比访问Bitmap对象的特定像素稍快。您也不需要一个未完成的位图对象,直到您的数组被填充。
数组内存访问是优化的,因为缓存了以下内存块(计算机预测,将有几个数组元素的访问,因此它可以缓存数组数据,因为它在内存中是顺序的)。位图也与数组相关联,但它是一个对象,因此访问其字段太频繁可能会有点慢。

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)
aurhwmvo

aurhwmvo2#

使用这种访问方式,一个接一个地迭代像素,看起来主要耗时的部分是 colorToHSV 函数。它计算的信息比所需的Value更多。
转换https://www.rapidtables.com/convert/color/rgb-to-hsv.html的描述
经过以下调整后,给定尺寸所需的时间从2.1秒减少到0.1秒。

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
    }

相关问题