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

Android开发:如何将Bitmap部分转为黑白,其余保留彩色?

嘿,这个需求我之前做类似的艺术化图片效果时折腾过,其实分两种场景来实现会更清晰——一种是整体按比例混合黑白与原色彩(比如60%的黑白质感+40%的彩色),另一种是指定区域比例转为黑白(比如图片60%的区域变成黑白,剩下保留彩色)。我给你具体说说两种方案的实现:

方案一:整体比例混合(推荐,性能更优)

这种适合做那种半黑白的艺术过渡效果,核心是用ColorMatrix来混合原色彩和黑白效果的比例,代码非常简洁:

// 假设你已经拿到了要处理的原Bitmap
val originalBitmap = ...
val blackWhiteRatio = 0.6f // 60%黑白,40%保留原色彩
val resultBitmap = Bitmap.createBitmap(
    originalBitmap.width, 
    originalBitmap.height, 
    originalBitmap.config
)
val canvas = Canvas(resultBitmap)

// 第一步:创建黑白化的ColorMatrix(饱和度设为0就是全黑白)
val bwMatrix = ColorMatrix()
bwMatrix.setSaturation(0f)

// 第二步:创建混合矩阵,让原色彩保留(1-ratio)的比例,黑白占ratio比例
val mixMatrix = ColorMatrix()
mixMatrix.setScale(
    1 - blackWhiteRatio, 
    1 - blackWhiteRatio, 
    1 - blackWhiteRatio, 
    1f
)
mixMatrix.postConcat(bwMatrix)

// 第三步:用混合矩阵创建ColorFilter,绘制到新Bitmap
val paint = Paint()
paint.colorFilter = ColorMatrixColorFilter(mixMatrix)
canvas.drawBitmap(originalBitmap, 0f, 0f, paint)

// 最后设置到ImageView
yourImageView.setImageBitmap(resultBitmap)

这段代码是通过GPU层面的着色器处理,比直接操作像素快很多,而且不会有明显的性能问题,适合大部分场景。

方案二:指定区域比例转为黑白

如果是要让图片的某一部分(比如60%的区域)变成黑白,剩下的保留彩色,那可以用遮罩或者直接绘制区域的方式实现。这里举两个常见的例子:

示例1:固定矩形区域(横向占60%)

val originalBitmap = ...
val targetRatio = 0.6f // 60%区域为黑白
val resultBitmap = Bitmap.createBitmap(
    originalBitmap.width, 
    originalBitmap.height, 
    originalBitmap.config
)
val canvas = Canvas(resultBitmap)

// 先绘制原彩色图片
canvas.drawBitmap(originalBitmap, 0f, 0f, null)

// 创建黑白效果的Paint
val bwPaint = Paint()
val bwMatrix = ColorMatrix()
bwMatrix.setSaturation(0f)
bwPaint.colorFilter = ColorMatrixColorFilter(bwMatrix)

// 计算黑白区域的宽度(横向占60%)
val bwWidth = (originalBitmap.width * targetRatio).toInt()
// 把对应区域的图片绘制成黑白,覆盖在原图片上
canvas.drawBitmap(
    originalBitmap, 
    Rect(0, 0, bwWidth, originalBitmap.height), 
    Rect(0, 0, bwWidth, originalBitmap.height), 
    bwPaint
)

yourImageView.setImageBitmap(resultBitmap)

示例2:随机不规则区域(60%面积为黑白)

如果想要更自然的随机黑白区域,可以用遮罩+Xfermode来实现:

val originalBitmap = ...
val targetRatio = 0.6f
val resultBitmap = Bitmap.createBitmap(
    originalBitmap.width, 
    originalBitmap.height, 
    originalBitmap.config
)
val canvas = Canvas(resultBitmap)

// 第一步:创建Alpha遮罩,生成60%面积的黑色区域(用来标记黑白范围)
val maskBitmap = Bitmap.createBitmap(
    originalBitmap.width, 
    originalBitmap.height, 
    Bitmap.Config.ALPHA_8
)
val maskCanvas = Canvas(maskBitmap)
val randomPaint = Paint().apply { color = Color.BLACK }

val totalPixels = originalBitmap.width * originalBitmap.height
var drawnPixels = 0
val targetPixels = (totalPixels * targetRatio).toInt()

// 随机绘制矩形,直到覆盖60%的像素
while (drawnPixels < targetPixels) {
    val x = Random.nextInt(originalBitmap.width)
    val y = Random.nextInt(originalBitmap.height)
    val w = Random.nextInt(originalBitmap.width - x)
    val h = Random.nextInt(originalBitmap.height - y)
    maskCanvas.drawRect(x.toFloat(), y.toFloat(), (x+w).toFloat(), (y+h).toFloat(), randomPaint)
    drawnPixels += w * h
}

// 第二步:用遮罩绘制黑白区域
val bwPaint = Paint().apply {
    val bwMatrix = ColorMatrix()
    bwMatrix.setSaturation(0f)
    colorFilter = ColorMatrixColorFilter(bwMatrix)
    // 只在遮罩的黑色区域绘制黑白效果
    xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
}

// 先画原彩色图,再画遮罩,最后画黑白图(只在遮罩区域生效)
canvas.drawBitmap(originalBitmap, 0f, 0f, null)
canvas.drawBitmap(maskBitmap, 0f, 0f, null)
canvas.drawBitmap(originalBitmap, 0f, 0f, bwPaint)

// 记得清空Xfermode,避免影响后续绘制
bwPaint.xfermode = null

yourImageView.setImageBitmap(resultBitmap)
一些注意事项
  • 如果处理的是大尺寸Bitmap,一定要注意内存问题!建议先用BitmapFactory.Options的inSampleSize采样缩小,避免OOM。
  • 方案一的性能远优于直接操作像素,优先考虑用ColorMatrix的方式。
  • 如果需要实时调整黑白比例(比如滑动条控制),可以把逻辑放到自定义ImageView的onDraw方法里,动态修改ratio值重新绘制即可。

内容的提问来源于stack exchange,提问作者KOG

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:29:11