如何修改Bitmap取色函数以选取图像中的深色而非浅色?
从Bitmap中提取深色主色调的实现方案
原函数通过将图片缩至1x1获取的是全局平均色,当画面浅色区域占比高时,结果自然偏浅。要提取深色主色调,可以通过筛选暗部像素或统计暗部颜色频率的方式实现,以下是两种可行方案:
方案一:筛选暗部像素计算平均色
先缩小图片降低计算量,再基于人眼感知的亮度公式筛选出深色像素,最后取这些像素的RGB平均值,避免浅色区域干扰:
import android.graphics.Bitmap import android.graphics.Color fun getDarkMainColor(img: Bitmap): Int { // 缩至32x32平衡计算性能与准确性,可按需调整尺寸 val scaledImg = Bitmap.createScaledBitmap(img, 32, 32, true) val width = scaledImg.width val height = scaledImg.height var totalR = 0 var totalG = 0 var totalB = 0 var darkPixelCount = 0 // 亮度阈值(0-255),值越低筛选出的颜色越暗,可根据UI需求调整 val darkBrightnessThreshold = 100 for (y in 0 until height) { for (x in 0 until width) { val color = scaledImg.getPixel(x, y) val r = Color.red(color) val g = Color.green(color) val b = Color.blue(color) // 人眼感知的亮度计算公式,比直接取RGB平均更准确 val brightness = (0.299 * r + 0.587 * g + 0.114 * b).toInt() if (brightness <= darkBrightnessThreshold) { totalR += r totalG += g totalB += b darkPixelCount++ } } } scaledImg.recycle() // 若没有符合条件的深色像素, fallback 到原全局平均色 return if (darkPixelCount > 0) { Color.rgb(totalR / darkPixelCount, totalG / darkPixelCount, totalB / darkPixelCount) } else { getMainColor(img) } } // 保留原函数作为 fallback fun getMainColor(img: Bitmap): Int { val newImg = Bitmap.createScaledBitmap(img, 1, 1, true) val color = newImg.getPixel(0, 0) newImg.recycle() return color }
方案二:提取暗部区域的主流色
统计所有像素的亮度,找到暗部区域中出现频率最高的颜色,结果比单纯取最暗像素更稳定:
import android.graphics.Bitmap import android.graphics.Color fun getDarkestDominantColor(img: Bitmap): Int { // 缩至64x64提升统计准确性,可按需调整 val scaledImg = Bitmap.createScaledBitmap(img, 64, 64, true) val width = scaledImg.width val height = scaledImg.height val colorFrequencyMap = mutableMapOf<Int, Int>() var darkestColor = scaledImg.getPixel(0, 0) var darkestBrightness = Int.MAX_VALUE for (y in 0 until height) { for (x in 0 until width) { val color = scaledImg.getPixel(x, y) val r = Color.red(color) val g = Color.green(color) val b = Color.blue(color) val brightness = (0.299 * r + 0.587 * g + 0.114 * b).toInt() // 更新当前最暗颜色 if (brightness < darkestBrightness) { darkestBrightness = brightness darkestColor = color } // 统计颜色出现次数 colorFrequencyMap[color] = colorFrequencyMap.getOrDefault(color, 0) + 1 } } scaledImg.recycle() // 从最暗颜色的相近范围内,找出出现频率最高的颜色 val darkColorCandidates = colorFrequencyMap.filter { entry -> val r = Color.red(entry.key) val g = Color.green(entry.key) val b = Color.blue(entry.key) val brightness = (0.299 * r + 0.587 * g + 0.114 * b).toInt() brightness <= darkestBrightness + 20 // 扩大范围避免极端暗像素的干扰 } // 返回频率最高的暗色调,若无则返回最暗像素 return darkColorCandidates.maxByOrNull { it.value }?.key ?: darkestColor }
注意事项
- 缩放图片的尺寸可根据性能需求调整:尺寸越大,结果越准确但计算耗时越长;
- 亮度阈值可灵活调整,数值越小,提取的颜色越深;
- 所有创建的临时Bitmap记得调用
recycle()释放内存,避免内存泄漏; - 两种方案都使用了符合人眼感知的亮度计算公式,比直接取RGB平均值更贴合视觉体验。
内容的提问来源于stack exchange,提问作者ShahZaman Rai
相关产品推荐
相关产品推荐

