如果您要使用“感知”哈希,并且只需要处理 64 个值,那么使用更高级的算法可能会很有趣。其背后的理论大致解释here。
灰色 = (0.2126×红色2.2 + 0.7152×绿色2.2 + 0.0722×蓝色2.2)1/2.2支持>
作为代码,这将成为
public static Byte GetGreyValue(Byte red, Byte green, Byte blue)
{
Double redFactor = 0.2126d * Math.Pow(red, 2.2d);
Double grnFactor = 0.7152d * Math.Pow(green, 2.2d);
Double bluFactor = 0.0722d * Math.Pow(blue, 2.2d);
Double grey = Math.Pow(redFactor + grnFactor + bluFactor, 1d / 2.2);
return (Byte)Math.Max(0, Math.Min(255, Math.Round(grey, MidpointRounding.AwayFromZero)));
}
现在您可以查看调整大小的图像中的所有字节并将它们转换为灰色。使用LockBits,这并不难。您只需将字节复制出来,每四个(每个 ARGB 字节四边形)迭代它们,取出 RGB 组件,将它们放入“make gray”函数中,将结果放入您从中获取它们的 RGB 点中,然后编写完成后将字节数组放回图像中。
public static Bitmap GetGreyImage(Image img, Int32 width, Int32 height)
{
// get image data
Bitmap b = new Bitmap(img, width, height);
BitmapData sourceData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
Int32 stride = sourceData.Stride;
Byte[] data = new Byte[stride * b.Height];
// Copy bytes from image into data array
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
// iterate over array and convert to gray
for (Int32 y = 0; y < height; y++)
{
Int32 offset = y * stride;
for (Int32 x = 0; x < width; x++)
{
// "ARGB" is little-endian Int32, so the actual byte order is B,G,R,A
Byte colB = data[offset + 0]; // B
Byte colG = data[offset + 1]; // G
Byte colR = data[offset + 2]; // R
Int32 colA = data[offset + 3]; // A
// Optional improvement: set pixels to black if color
// is considered too transparent to matter.
Byte grayValue = colA < 128 ? 0 : GetGreyValue(colR, colG, colB);
data[offset + 0] = grayValue; // B
data[offset + 1] = grayValue; // G
data[offset + 2] = grayValue; // R
data[offset + 3] = 0xFF; // A
offset += 4;
}
}
// Copy bytes from data array back into image
Marshal.Copy(data, 0, sourceData.Scan0, data.Length);
b.UnlockBits(sourceData);
return b;
}
如果使用“从 64 种红色、64 种绿色和 64 种蓝色变为 64 种总颜色”,您的意思是您想要一个 8 位(调色板)图像,其中每个字节是一个像素,那么您将不得不简单地将在那里生成的值保存在一个新的字节数组中,而不是将它们写回,然后使用Format8bppIndexed 格式创建一个新的 8x8 位图,在第二个 BitmapData 对象中打开它,然后将其写入其中。
请注意,8 位图像需要一个调色板,因此您需要检查标准生成的 8 位图像调色板并将其更改为从 (0,0,0) 到 (255,255,255) 的淡入淡出) 带有for 循环。