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

Java如何实现RGB图像转灰度图且保留指定单一颜色(红色)

保留红色区域其余转灰度的BMP图像处理方案

需求

实现类似《罪恶之城》的影视特效,将24位BMP图像中除红色区域外的所有内容转为灰度,仅保留红色区域的原色。

现有代码问题

你写的代码有三处核心错误,导致无法得到预期效果:

  1. 逻辑完全颠倒:判定像素偏红时修改了蓝绿通道为灰度值,非红区域反而保留了原色,和需求相反
  2. 红色判定规则过松:仅判断R通道为最大值会误把大量偏橙、偏粉的浅暖色都判定为红色保留,最终效果杂乱
  3. 未处理BMP行对齐规则:BMP要求每行像素数据的字节数必须对齐到4的倍数,不足的会补填充字节,直接按3字节一组读取会导致宽度不是4的倍数的图像输出错位、损坏

修正后可运行代码

package poza;
import java.io.*;

public class poza {

    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("poza.bmp");
            BufferedInputStream dis = new BufferedInputStream(fis);
            FileOutputStream sif = new FileOutputStream("poza1.bmp");
            BufferedOutputStream bos = new BufferedOutputStream(sif);
            
            // 读取并原样写入BMP文件头
            byte[] header = new byte[54];
            dis.read(header, 0, 54);
            bos.write(header);
            
            // 从文件头读取图像宽度,计算行填充字节数
            int width = ((header[21] & 0xff) << 24) | ((header[20] & 0xff) << 16) | ((header[19] & 0xff) << 8) | (header[18] & 0xff);
            int rowByteCount = (width * 3 + 3) / 4 * 4;
            int paddingByteCount = rowByteCount - width * 3;

            while (dis.available() > 0) {
                // 遍历当前行所有像素
                for (int i = 0; i < width; i++) {
                    int b = dis.read() & 0xff;
                    int g = dis.read() & 0xff;
                    int r = dis.read() & 0xff;

                    int gray = (int) (0.114 * b + 0.587 * g + 0.299 * r);
                    // 红色判定阈值可自行调整,数值越大保留的红色范围越小
                    if (r > g + 30 && r > b + 30) {
                        // 红色区域保留原色
                        bos.write(b);
                        bos.write(g);
                        bos.write(r);
                    } else {
                        // 非红色区域转灰度
                        bos.write(gray);
                        bos.write(gray);
                        bos.write(gray);
                    }
                }
                // 原样写入行填充字节
                for (int i = 0; i < paddingByteCount; i++) {
                    bos.write(dis.read());
                }
            }

            dis.close();
            bos.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

调整说明

代码里红色判定的阈值30可以根据你想要的效果灵活修改:阈值越小,会保留越多偏红的暖色区域;阈值越大,仅会保留非常鲜艳的纯红色区域。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 21:27:04