You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:50:47