2014-01-30 78 views
1
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

您對LINQ和功能組合的使用非常好。 – usr

+0

@usr所有的LINQ代碼都不是我的。我很少知道它是誠實的 – puretppc

+0

GetIndexedImage可以作爲方法組調用。 – Magus

回答

0

您正在對byte[]進行分組。不幸的是,.NET集合不支持相等和哈希。這意味着您默認獲得參考比較。 (我的觀點:這是.NET框架中的一個設計缺陷,應該沒有默認的相等性,在這種情況下應該拋出一個錯誤。)

自己寫一個IEqualityComparer<byte[]>

另外,您在分組之前進行訂購。分組不保存排序。文檔不能保證它不能被依賴。事實上,它並不適用於實踐。

+0

僅僅因爲另一方的知情決定與您的個人期望不符,不會使其成爲設計缺陷。這就像你的意見。 – Magus

+0

@Magus我同意。我現在已經說得很清楚了。 – usr

+0

我相信他需要寫一個'IEqualityComparer >'而不是'IEqualityComparer'。如果你想使用IEqualityComparer 你可以,但我建議將最後兩個LINQ語句改爲單個'.GroupBy(t => HashImage(t.Item2),t => t,new YourComparer()) '(這使'GroupBy'返回原始元組作爲散列鍵的值,因此您可以使用舊索引在foreach foreach中進行排序(var in group.OrderBy(t => t.Item1))'') –