Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Сравнение 2х картинок  [new]
Супер_Пав
Member

Откуда: Москва
Сообщений: 347
День добрый.
Как сравнить 2 JPG файла? Думал, что GetHashCode поможет мне, но метод выдает всегда разные значения для одного файла.
Нашел такой способ:
public static List<bool> GetHash(Bitmap bmpSource)
{
    List<bool> lResult = new List<bool>();         
    //create new image with 16x16 pixel
    Bitmap bmpMin = new Bitmap(bmpSource, new Size(16, 16));
    for (int j = 0; j < bmpMin.Height; j++)
    {
        for (int i = 0; i < bmpMin.Width; i++)
        {
            //reduce colors to true / false                
            lResult.Add(bmpMin.GetPixel(i, j).GetBrightness() < 0.5f);
        }             
    }
    return lResult;
}
List<bool> iHash1 = GetHash(new Bitmap(@"C:\mykoala1.jpg"));
List<bool> iHash2 = GetHash(new Bitmap(@"C:\mykoala2.jpg"));

//determine the number of equal pixel (x of 256)
int equalElements = iHash1.Zip(iHash2, (i, j) => i == j).Count(eq => eq);

Но какое-то сомнительное занятие пробегать по всем пикселям, учитывая, что картинок тысячи и проверка проводится каждые 10 минут.
11 мар 19, 13:56    [21829163]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3305
Для объектов ссылочного типа не переопределенный метод GetHashCode возвращает хеш-код основанный на адресе объекта в памяти,
то есть создав 2 одинаковый объекта ссылочного типа (class) у них будет разный хеш-код, потому, что каждый экземпляр хранится отдельно, но если две ссылки указывают на один объект, значение будут равны.
Переопределите метод GetHashCode.
А вообще для сравнения больших файлов лучше использовать не хеширование, а контрольную сумму типа CRC32 или другие подобные алгоритмы.
Если переопределяете метод GetHashCode переопределите сразу метод Equals().
Типа значения поддерживают хеширование из коробки, но базовый метод адски тормозной, по этому, лучше его тоже переопределять
11 мар 19, 14:03    [21829177]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Супер_Пав
Member

Откуда: Москва
Сообщений: 347
Roman Mejtes
Для объектов ссылочного типа не переопределенный метод GetHashCode возвращает хеш-код основанный на адресе объекта в памяти,
то есть создав 2 одинаковый объекта ссылочного типа (class) у них будет разный хеш-код, потому, что каждый экземпляр хранится отдельно, но если две ссылки указывают на один объект, значение будут равны.
Переопределите метод GetHashCode.
А вообще для сравнения больших файлов лучше использовать не хеширование, а контрольную сумму типа CRC32 или другие подобные алгоритмы.
Если переопределяете метод GetHashCode переопределите сразу метод Equals().
Типа значения поддерживают хеширование из коробки, но базовый метод адски тормозной, по этому, лучше его тоже переопределять

я затупил. По первой ссылке в гугле нашел метод GetHashCode и не стал читать его описание, подумал, что для одной картинки всегда будет один результат. Сейчас уже понимаю, что метод не подходит.
11 мар 19, 14:10    [21829187]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Dima T
Member

Откуда:
Сообщений: 13623
Сравнение изображений
11 мар 19, 14:13    [21829193]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38457
Супер_Пав
Как сравнить 2 JPG файла?
а почему не музыкальный файл?
Сравниваем образы, фото, силуэты, пиксели, компрессию?
11 мар 19, 14:38    [21829219]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Супер_Пав
Member

Откуда: Москва
Сообщений: 347
Petro123
Супер_Пав
Как сравнить 2 JPG файла?
а почему не музыкальный файл?
Сравниваем образы, фото, силуэты, пиксели, компрессию?

на самом деле не важно какой файл. Просто в моем случае это JPG. Но мне не важны детали, которые различают файлы, важна контрольная сумма
11 мар 19, 15:07    [21829254]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38457
Супер_Пав
важна контрольная сумма
она строится по деталям.
Иначе размер файла сравнивайте.
11 мар 19, 15:12    [21829265]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 4710
[quot Супер_ПавНо мне не важны детали, которые различают файлы, важна контрольная сумма[/quot]
https://www.google.com/search?q=C# file hash
12 мар 19, 06:12    [21829907]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3305
static void Main(string[] args)
{
    var rsaHash = System.Security.Cryptography.SHA256.Create();
    using (var fileStream = File.Open(@"C:\MyFile.jpg", FileMode.Open))
    {
        var hash = rsaHash.ComputeHash(fileStream);
        var str = string.Join("", hash.Select(p => p.ToString("x2")));
        Console.WriteLine(str);
        Console.ReadKey();
    }
}
12 мар 19, 12:40    [21830141]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3305
контрольная сумма CRC32
using System.Security.Cryptography;
using System.IO;

public class Crc32 : HashAlgorithm
{
    public const uint DefaultPolynomial = 0xEDB88320;
    public const uint DefaultSeed = 0xffffffff;

    private uint _hash;

    private readonly uint _seed;
    private readonly uint[] _table;

    private static uint[] defaultTable;

    public Crc32()
    {
        _table = InitializeTable(DefaultPolynomial);
        _seed = DefaultSeed;
        Initialize();
    }

    public Crc32(uint polynomial, uint seed)
    {
        _table = InitializeTable(polynomial);
        _seed = seed;
        Initialize();
    }

    public override void Initialize()
    {
        _hash = _seed;
    }

    protected override void HashCore(byte[] buffer, int start, int length)
    {
        _hash = CalculateHash(_table, _hash, buffer, start, length);
    }

    protected override byte[] HashFinal()
    {
        byte[] hashBuffer = UInt32ToBigEndianBytes(~_hash);
        HashValue = hashBuffer;
        return hashBuffer;
    }

    public override int HashSize
    {
        get { return 32; }
    }

    /// <summary> Рассчитывает контрольную сумму </summary>
    /// <param name="buffer">Буфер данных</param>
    /// <returns>Контрольная сумма</returns>
    public static uint Compute(byte[] buffer)
    {
        return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length);
    }

    /// <summary> Рассчитывает контрольную сумму </summary>
    /// <param name="seed">Начальное значение</param>
    /// <param name="buffer">Буфер данных</param>
    /// <returns>Контрольная сумма</returns>
    public static uint Compute(uint seed, byte[] buffer)
    {
        return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length);
    }

    /// <summary> Рассчитывает контрольную сумму </summary>
    /// <param name="polynomial">Порождающий полином</param>
    /// <param name="seed">Начальное значение</param>
    /// <param name="buffer">Буфер данных</param>
    /// <returns>Контрольная сумма</returns>
    public static uint Compute(uint polynomial, uint seed, byte[] buffer)
    {
        return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
    }

    /// <summary> Инициализирует таблицу со значением полинома для каждого значения байта, чтоб не расчитывать их в процессе </summary>
    /// <param name="polynomial">Порождающий полином</param>
    private static uint[] InitializeTable(uint polynomial)
    {
        if (polynomial == DefaultPolynomial && defaultTable != null)
            return defaultTable;

        uint[] createTable = new uint[256];
        for (int i = 0; i < 256; i++)
        {
            uint entry = (uint)i;
            for (int j = 0; j < 8; j++)
            {
                if ((entry & 1) == 1)
                    entry = (entry >> 1) ^ polynomial;
                else
                    entry = entry >> 1;
            }

            createTable[i] = entry;
        }

        if (polynomial == DefaultPolynomial)
            defaultTable = createTable;

        return createTable;
    }

    private static uint CalculateHash(uint[] table, uint seed, byte[] buffer, int start, int size)
    {
        uint crc = seed;
        for (int i = start; i < size; i++)
        {
            unchecked
            {
                crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff];
            }
        }
        return crc;
    }

    /// <summary> Преобразует результат вычисления хеша в 4 байта с инвертированием битов </summary>
    private static byte[] UInt32ToBigEndianBytes(uint x)
    {
        return new byte[] {
            (byte)((x >> 24) & 0xff),
            (byte)((x >> 16) & 0xff),
            (byte)((x >> 8) & 0xff),
            (byte)(x & 0xff)
        };
    }

    /// <summary> Рассчитывает контрольную сумму файла и возвращает её в виде 16 битного значения в строке </summary>
    public static string Get(string file)
    {
        Crc32 crc32 = new Crc32();
        string hash = string.Empty;

        using (FileStream fs = File.Open(file, FileMode.Open))
        {
            foreach (byte b in crc32.ComputeHash(fs))
            {
                hash += b.ToString("x2").ToLower();
            }
        }
        return hash;
    }
}
12 мар 19, 13:07    [21830180]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Dima T
Member

Откуда:
Сообщений: 13623
CRC32 медленно считается. В инете нашел алгоритм попроще. Если в инете не наврали, то используется для расчет хэша строк у МС в С++.
uint32_t hash32(const char* str) {
	uint32_t h = 0;
	while (*str) h = (h << 5) + h + *str++;
	return h;
}

Я слегка модифицировал под расчет хэша заданного блока памяти
uint32_t hash32(const void* data, size_t len, uint32_t prev = 0) {
	const char* str = (const char*) data;
	uint32_t h = prev;
	while (len--) h = (h << 5) + h + *str++;
	return h;
}

Думаю под C# несложно переписать. Можно переделать на 64 бита, просто заменить uint32_t на uint64_t
12 мар 19, 13:50    [21830230]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Супер_Пав
Member

Откуда: Москва
Сообщений: 347
Ого, тема получила продолжение, не ожидал.
Я взял для себя расчет мд5 и сравнение размера файла. Для меня не важно детальное сравнение файлов, важно знать, были ли изменения
public static string ComputeMd5Checksum(string path)
{
    using (var fs = File.OpenRead(path))
    using (MD5 md5 = new MD5CryptoServiceProvider())
    {
        var checkSum = md5.ComputeHash(fs);
        var result = BitConverter.ToString(checkSum).Replace("-", string.Empty);
        return result;
    }
}
12 мар 19, 17:52    [21830597]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
PinkCat
Member [заблокирован]

Откуда:
Сообщений: 2421
Супер_Пав,

Для меня не важно детальное сравнение файлов, важно знать, были ли изменения
-----
Открой для себя:
[url=]https://docs.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?view=netframework-4.7.2[/url]
будешь получать нотификацию изменений по настроенным фильтрам.
По крайней мере не нужно будет сканить все каждые 10 минут.
12 мар 19, 18:27    [21830631]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
Супер_Пав
Member

Откуда: Москва
Сообщений: 347
PinkCat, у меня файлы в сети. FileWatcher я пробовал в 1ю очередь, были какие-то проблемы, точно уже не помню
12 мар 19, 18:55    [21830645]     Ответить | Цитировать Сообщить модератору
 Re: Сравнение 2х картинок  [new]
PinkCat
Member [заблокирован]

Откуда:
Сообщений: 2421
Супер_Пав,

были какие-то проблемы
-----
Были, решал => работало.
Правда потом отказался - нашлось более приемлемое решение, чем следить за состоянием системы.
12 мар 19, 19:46    [21830674]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить