Как быстрее всего сравнить два растровых изображения одинакового размера, чтобы определить, являются ли они идентичными?

Все говорят о высоте, но мой TableView в StackView с ведущим выравниванием заканчивается шириной 0.

Убедитесь, что ваш TableView имеет правильный размер, используя Debug View Hierarchy.

37
задан Erik Forbes 10 January 2010 в 20:37
поделиться

8 ответов

Редактирование 8-31-12: в соответствии с комментарием Джоуи ниже, помните о формате сравниваемых битовых карт. Они могут содержать отступы по шагам, которые делают битовые карты неравномерными, несмотря на то, что они эквивалентны по пикселям. Подробнее см. в этом вопросе .


Чтение этого ответа на вопрос относительно сравнения массивов байт привело к использованию метода MUCH FASTER: с использованием P/Invoke и вызова memcmp API в msvcrt. Вот код:

[DllImport("msvcrt.dll")]
private static extern int memcmp(IntPtr b1, IntPtr b2, long count);

public static bool CompareMemCmp(Bitmap b1, Bitmap b2)
{
    if ((b1 == null) != (b2 == null)) return false;
    if (b1.Size != b2.Size) return false;

    var bd1 = b1.LockBits(new Rectangle(new Point(0, 0), b1.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    var bd2 = b2.LockBits(new Rectangle(new Point(0, 0), b2.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    try
    {
        IntPtr bd1scan0 = bd1.Scan0;
        IntPtr bd2scan0 = bd2.Scan0;

        int stride = bd1.Stride;
        int len = stride * b1.Height;

        return memcmp(bd1scan0, bd2scan0, len) == 0;
    }
    finally
    {
        b1.UnlockBits(bd1);
        b2.UnlockBits(bd2);
    }
}
34
ответ дан 27 November 2019 в 03:41
поделиться
[

] Если вы пытаетесь определить, равны ли они на 100%, вы можете инвертировать один и добавить его к другому, если его ноль совпадает. Расширяя это, используя небезопасный код, берите 64 бита за раз и делайте подсчет таким образом, любые различия могут привести к немедленному провалу.[

] [

]Если изображения не на 100% идентичны (сравнивая png с jpeg), или если вы не ищете 100%-ое совпадение, то у вас есть еще кое-какая работа.[

] [

]Удачи.[

]
9
ответ дан 27 November 2019 в 03:41
поделиться
[

] Не могли бы вы взять по гашишу и сравнить? Это было бы несколько вероятностно, но практически нет. [

] [

] Благодаря Раму, вот [] пример реализации [] этой методики. [

].
6
ответ дан 27 November 2019 в 03:41
поделиться
[

]Вы можете попробовать добавить их в "blob" базы данных, а затем использовать движок базы данных для сравнения их двоичных файлов. Это даст вам только ответ "да" или "нет" на вопрос, являются ли двоичные данные одинаковыми. Было бы очень просто сделать 2 изображения, которые создают одну и ту же графику, но имеют разные двоичные данные.[

] [

]Вы также можете выбрать несколько случайных пикселей и сравнить их, а затем, если они одинаковые, продолжить с большим количеством, пока вы не проверите все пиксели. Это только вернет более быстрое отрицательное совпадение, но все равно потребуется столько же времени, чтобы найти 100% положительное совпадение [

].
0
ответ дан 27 November 2019 в 03:41
поделиться
[

] Если Вы можете реализовать что-то вроде []Duff's Device [] на Вашем языке, это может дать Вам значительный прирост скорости за простой цикл. Обычно оно используется для копирования данных, но нет причин, по которым оно не может быть использовано для сравнения данных.[

] [

]Или, если на то пошло, Вы можете просто использовать какой-нибудь эквивалент memcmp().[

].
0
ответ дан 27 November 2019 в 03:41
поделиться

Если исходная задача состоит в том, чтобы найти точные дубликаты между двумя битовыми картами, то потребуется лишь сравнение по битовому уровню. Я не знаю C#, но в C я бы использовал следующую функцию:

int areEqual (long size, long *a, long *b)
{
    long start = size / 2;
    long i;
    for (i = start; i != size; i++) { if (a[i] != b[i]) return 0 }
    for (i = 0; i != start; i++) { if (a[i] != b[i]) return 0 }
    return 1;
}

Я бы начал искать в середине, потому что подозреваю, что шансы найти неравные биты рядом с серединой изображения намного выше, чем в начале; конечно, это действительно будет зависеть от того, какие изображения вы дедуцируете, выбор случайного места для начала, возможно, будет лучшим вариантом.

Если вы пытаетесь найти точные дубликаты среди сотен изображений, то сравнение всех пар из них ненужно. Сначала вычислите MD5 хэш каждого изображения и поместите его в список пар (md5Hash, imageId); затем отсортируйте список по m5Hash. Затем делаем парные сравнения только на тех изображениях, которые имеют одинаковый md5Hash.

3
ответ дан 27 November 2019 в 03:41
поделиться

Ну, вы используете .LockBits, так что предположительно вы используете небезопасный код. Вместо того, чтобы трактовать происхождение каждого ряда (Scan0 + y * Stride) как байт*, считайте, что это int*; int арифметика довольно быстрая, и вам нужно сделать только 1/4 от объема работы. А для изображений в ARGB вы, возможно, все еще говорите в пикселях, делая математику простой.

8
ответ дан 27 November 2019 в 03:41
поделиться
- 4378949-

Если эти растровые изображения уже на вашей видеокарте, вы можете распараллелизировать такой чек, делая его на графической карте, используя язык, например CUDA или Opencl .

Я объясню с точки зрения Куда, поскольку это тот, который я знаю. В основном CUDA позволяет писать код общего назначения для работы параллельно на каждом узле вашей видеокарты. Вы можете получить доступ к ратушам, которые находятся в общей памяти. Каждый вызов функции также учитывается индекс в пределах набора параллельных прогонов. Итак, для такой проблемы, вы просто запустите одно из вышеупомянутых функций сравнения для некоторого подмножества растрового изображения - с использованием параллелизации, чтобы покрыть весь растровый кармал. Тогда просто напишите 1 на определенное местоположение памяти, если сравнение не удается (и ничего не писать, если это удастся).

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

Вот какой-то (довольно плохой) пример код (прошел немного, так как я запрограммировал CUDA). Есть лучшие способы получить доступ к ратушам, которые уже загружены как текстуры, но я не беспокоился здесь.

// kernel to run on GPU, once per thread
__global__ void compare_bitmaps(long const * const A, long const * const B, char * const retValue, size_t const len)
{
 // divide the work equally among the threads (each thread is in a block, each block is in a grid)
 size_t const threads_per_block = blockDim.x * blockDim.y * blockDim.z;
 size_t const len_to_compare = len / (gridDim.x * gridDim.y * gridDim.z * threads_per_block);
# define offset3(idx3,dim3)  (idx3.x + dim3.x * (idx3.y + dim3.y * idx3.z))
 size_t const start_offset = len_to_compare * (offset3(threadIdx,blockDim) + threads_per_block * offset3(blockIdx,gridDim));
 size_t const stop_offset = start_offset + len_to_compare;
# undef offset3

 size_t i;
 for (i = start_offset; i < stop_offset; i++)
 {
  if (A[i] != B[i]) 
  {
   *retValue = 1;
   break;
  }
 }
 return;
}
3
ответ дан 27 November 2019 в 03:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: