Подходим два одинаковых изображения с разными именами файлов - PullRequest
3 голосов
/ 13 мая 2011

если одно изображение было сохранено дважды с двумя разными именами файлов, есть ли способ сравнить их, чтобы увидеть, совпадают ли они? .. *

Я надеюсь, что базовый хэш или тип CRCпроверка может работать ..?

Размер файла может не совпадать, так как в пуле миллионы изображений и разные изображения могут иметь одинаковый размер ..

Надеюсь, что это простой способ сделать этов C # ..

Ответы [ 5 ]

7 голосов
/ 13 мая 2011

Если содержимое файла идентично, то криптографический хэш, по крайней мере, очень хорошо показывает равенство.Класс SHA256 был бы хорошим кандидатом здесь, хотя это, возможно, немного выше.Например:

static byte[] Sha256HashFile(string file)
{
    using (SHA256 sha256 = SHA256.Create())
    {
        using (Stream input = File.OpenRead(file))
        {
            return sha256.ComputeHash(input);
        }
    }
}

Самый простой способ сравнить два возвращенных байтовых массива - это, вероятно, преобразовать их оба в строки, используя Convert.ToBase64, а затем сравнить строки.Уродливо, но легко :) Вы также можете использовать Enumerable.SequenceEqual:

byte[] hash1 = Sha256HashFile("file1.png");
byte[] hash2 = Sha256HashFile("file2.png");
bool same = hash1.SequenceEqual(hash2);    

Если вы хотите сохранить хеши в виде набора или словаря, вы можете реализовать свой собственный IEqualityComparer<byte[]>, ночестно говоря, было бы проще всего использовать строку base64.Например, при этом будут распечатаны дубликаты файлов:

var hashToNameMap = new Dictionary<string, string>();
foreach (string file in files)
{
    byte[] hash = Sha256HashFile(file);
    string base64 = Convert.ToBase64(hash);
    string existingName;
    if (hashToNameMap.TryGetValue(base64, out existingName))
    {
        Console.WriteLine("{0} is a duplicate of {1}", file, existingName);
    }
    else
    {
        hashToNameMap[base64] = file;
    }
}

Несколько примечаний:

  • Это не гарантировано , чтобы быть точным, ношансы получить столкновение очень малы, особенно если файлы также должны быть действительными изображениями.
  • Это включает чтение всех из каждого файла - даже если естьнет других файлов с таким же размером (и, следовательно, нет возможных дубликатов).Это может или не может быть проблемой для вас.
  • Даже если в есть несколько файлов одинакового размера, вам нужно только прочитать все из них, чтобы найти дубликаты ... вы можетеПотенциально читайте файлы и вычисляйте хэши по ходу работы, останавливаясь, как только вы обнаружите, что файлы разные.

То, как вы к этому подходите, зависит от того, является ли ваша цель абсолютной скоростью, простотой кода и т. дЭто также может зависеть от того, будет ли пул расти со временем - например, вы можете захотеть хэшировать файлы, как только вы получите два или более файлов одинакового размера, чтобы при добавлении другого файла того же размера вы моглихэш , и добавьте его, даже не перечитывая существующие данные.

4 голосов
/ 13 мая 2011

Во-первых, все равно проверьте длину. Только когда они совпадают, нужно смотреть глубже.

Для всех изображений одинакового размера вычислите хэш. Когда хэши совпадают, вы можете быть уверены, что изображения идентичны. Библиотека предлагает множество криптографически безопасных хэшей, но вы можете поискать оптимизации:

  • Образец. Если ваши изображения имеют большой размер (> 100 кБ), вы можете сэкономить на вводе-выводе, вычисляя хэш только для нескольких сегментов. Возможно, достаточно нескольких килобайт в начале, середине и конце, чтобы получить хороший отпечаток. Используйте размеры 512 для размеров и смещений этих блоков. Сжатие Jpeg работает немного как хэш: разница в несколько пикселей обычно приводит к большим различиям в битовом потоке.

  • используйте более быстрый хеш. В этом случае может быть достаточно простого алгоритма xor.

  • Если вы действительно хотите сравнивать 2 изображения одновременно, используйте реализацию Hash, которая позволяет вам проверять промежуточные результаты. Как только есть разница, ты можешь остановиться.

  • Но если у вас много файлов одинакового размера, вычислите хэш один раз для каждого файла и найдите дубликаты (размер, хэш).
1 голос
/ 13 мая 2011

в

System.Security.Cryptography;

использовать SHA1

using(SHA1 sha = SHA1.Create()) { //added using based on Jon Skeet comment
    byte[] newData = sha.ComputeHash(data);
}

данные - это байт [] данные файла

newData - хеш

Это подходит только в том случае, если вы хотите знать, являются ли два файла изображений буквально одними и теми же байтами, а не если они просто кодируют одни и те же пиксели (которые могут быть разными файлами, если метаданные отличаются)

0 голосов
/ 13 мая 2011

Вы также можете сделать что-то вроде этого

public string ImageToBase64(Image image, 
                            System.Drawing.Imaging.ImageFormat format)
{ 
    using (MemoryStream ms = new MemoryStream())
    { 
         // Convert Image to byte[]
         image.Save(ms, format);  
         byte[] imageBytes = ms.ToArray();

        // Convert byte[] to Base64 String
        string base64String = Convert.ToBase64String(imageBytes);
        return base64String; 
    }
}

тогда вы можете просто сделать String.Compare(). Это, вероятно, медленно для больших изображений, потому что это генерирует довольно большую строку, но я разместил ее только ради завершений:)

0 голосов
/ 13 мая 2011

Вы можете прочитать двоичный файл из каждого файла и затем сравнить содержащийся двоичный файл. Одно и то же изображение должно иметь одинаковый двоичный файл в каждом массиве.

Просто мысль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...