如何在C#中按指定最大色深从屏幕获取像素颜色
C# 实现 Clickermann ColorMode(n) 等效色深压缩功能
核心实现逻辑
Clickermann 的 ColorMode(n) 本质是通过位量化机制压缩图像调色板,核心特性是按亮度层级合并相近颜色,不会在渐变区域出现突兀的色阶断层。
要对齐该功能效果,核心要遵循两个规则:
- 按人眼对色彩的敏感度分配位宽:绿色通道分配最多有效位,红色次之,蓝色最少,保证人眼感知最自然
- 对每个颜色通道做整层级量化,不做随机颜色映射,保证渐变区域的过渡连贯性
关键参数匹配
你给出的效果参考中,最大色深为8指总色深位宽为8,对应RGB通道的位宽分配为:绿色通道3位、红色通道3位、蓝色通道2位,总位宽刚好8位,和官方实现的效果对齐。
实现步骤
- 获取屏幕指定区域的原始像素数据,通过内存块直接操作像素,避免逐像素API带来的性能损耗
- 根据传入的总色深值,按优先级计算RGB三个通道各自的有效位宽
- 对每个通道的0-255亮度值计算对应量化步长,把同层级的相近颜色合并到同一亮度值
- 重组量化后的像素数据,输出处理后的图像
示例代码
首先引入依赖命名空间:
using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices;
屏幕区域捕获方法:
public static Bitmap CaptureScreenRegion(Rectangle captureArea) { Bitmap captureResult = new Bitmap(captureArea.Width, captureArea.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(captureResult)) { g.CopyFromScreen(captureArea.Left, captureArea.Top, 0, 0, captureArea.Size); } return captureResult; }
色深压缩核心方法:
public static Bitmap ApplyColorMode(Bitmap source, int totalColorDepth) { // 校验参数范围:总色深最大24位(无透明通道的真彩) if (totalColorDepth < 1 || totalColorDepth > 24) throw new ArgumentOutOfRangeException(nameof(totalColorDepth), "色深参数需在1-24区间内"); // 按人眼敏感度分配位宽:绿色通道最多,红色次之,蓝色最少 int bitsGreen = totalColorDepth / 3 + (totalColorDepth % 3 != 0 ? 1 : 0); int bitsRed = (totalColorDepth - bitsGreen) / 2; int bitsBlue = totalColorDepth - bitsGreen - bitsRed; // 计算每个通道的量化步长 int stepRed = 256 / (1 << bitsRed); int stepGreen = 256 / (1 << bitsGreen); int stepBlue = 256 / (1 << bitsBlue); // 锁定位图内存,直接操作字节数组提升处理速度 Rectangle imageRect = new Rectangle(0, 0, source.Width, source.Height); BitmapData rawData = source.LockBits(imageRect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); int bufferSize = Math.Abs(rawData.Stride) * source.Height; byte[] pixelBuffer = new byte[bufferSize]; Marshal.Copy(rawData.Scan0, pixelBuffer, 0, bufferSize); // 遍历所有像素执行量化 // 32位ARGB像素的内存顺序为B、G、R、A,每4字节对应一个像素 for (int i = 0; i < pixelBuffer.Length; i += 4) { pixelBuffer[i] = (byte)((pixelBuffer[i] / stepBlue) * stepBlue); pixelBuffer[i+1] = (byte)((pixelBuffer[i+1] / stepGreen) * stepGreen); pixelBuffer[i+2] = (byte)((pixelBuffer[i+2] / stepRed) * stepRed); } // 将处理后的数据写回位图 Marshal.Copy(pixelBuffer, 0, rawData.Scan0, bufferSize); source.UnlockBits(rawData); return source; }
使用示例
如果要实现等效于 Clickermann ColorMode(8) 的效果,直接调用方法即可:
// 捕获整个屏幕 Rectangle screenArea = Screen.PrimaryScreen.Bounds; Bitmap screenCapture = CaptureScreenRegion(screenArea); // 应用8位总色深压缩 Bitmap processed = ApplyColorMode(screenCapture, 8);
效果说明
该实现的量化规则会把相近颜色归到同一亮度层级,对渐变区域的处理和参考效果一致,不会出现随机色值跳变;处理大尺寸截图时,直接操作内存数组的性能比逐像素调用GetPixel/SetPixel高2个数量级以上。如果需要对齐 Clickermann 的具体位宽分配规则,只需要调整方法内的bitsGreen、bitsRed、bitsBlue三个变量的计算逻辑即可。
内容的提问来源于stack exchange,提问作者FreePhoenix888
相关产品推荐
相关产品推荐

