public byte[] HashImage(string fileName)
{
using (var image = new Bitmap(fileName))
{
var sha256 = SHA256.Create();
var rect = new Rectangle(0, 0, image.Width, image.Height);
var data = image.LockBits(rect, ImageLockMode.ReadOnly, image.PixelFormat);
var dataPtr = data.Scan0;
var totalBytes = (int)Math.Abs(data.Stride) * data.Height;
var rawData = new byte[totalBytes];
System.Runtime.InteropServices.Marshal.Copy(dataPtr, rawData, 0, totalBytes);
image.UnlockBits(data);
return sha256.ComputeHash(rawData);
}
}
private Tuple<int, string> GetIndexedImage(string fileName)
{
var baseFileName = Path.GetFileNameWithoutExtension(fileName);
int index;
if (int.TryParse(baseFileName, out index))
{
return Tuple.Create(index, fileName);
}
return null;
}
private string HashToString(byte[] hash)
{
var builder = new StringBuilder();
foreach (var b in hash)
{
builder.AppendFormat("{0:x2}", b);
}
return builder.ToString();
}
HashImage()
将图像的SHA256哈希值作为字节。
GetFileIndex()
返回索引和文件名的元组。
HashToString()
是一个字符串构建器,它将哈希值转换为字符串。
private void button1_Click(object sender, EventArgs e)
{
string original = @"C:\Users\user\Documents\CaptchaCollection\";
var equivalentImages = Directory.GetFiles(original)
.Select(f => GetIndexedImage(f)) // build tuples (index, fileName) or null if parsing failed
.Where(t => t != null) // ignore all invalid ones
.OrderBy(t => t.Item1) // order by index
.Select(t => Tuple.Create(HashImage(t.Item2), t.Item2)) // create new tuple (hash, fileName)
.GroupBy(t => t.Item1); // group by Hash
// print groups
foreach (var group in equivalentImages)
{
Console.WriteLine("All images with hash: {0}", HashToString(group.Key));
foreach (var t in group)
{
Console.WriteLine("\t{0}", t.Item2);
}
}
}
现在这就像是一个主要方法,当我点击按钮时,我开始得到图像文件的哈希值。
然而,现在主要的问题是,当我从文件中收集哈希的output时,它们似乎没有分组,而是按顺序打印。相反,它们遍布输出文件。
如何将具有相同散列的任何组和重复元素分组?
答案 0 :(得分:0)
您正在byte[]
进行分组。不幸的是,.NET集合不支持相等和散列。这意味着您默认获得参考比较。 (我的观点:这是.NET框架中的一个设计缺陷。应该没有默认的相等。在这种情况下应该抛出错误。)
给自己写一个IEqualityComparer<byte[]>
。
此外,您在分组前订购。分组不会保留订购。文档并不能保证不会被依赖。事实上,它并没有实践。