Порівняння зображень - швидкий алгоритм


393

Я хочу створити базову таблицю зображень, а потім порівняти будь-які нові зображення з цим, щоб визначити, чи нове зображення є точним (або близьким) дублікатом бази.

Наприклад: якщо ви хочете зменшити зберігання одного і того ж зображення в 100 разів, ви можете зберегти одну його копію та надати посилання на неї. Коли вводиться нове зображення, ви хочете порівняти його з існуючим зображенням, щоб переконатися, що це не дублікат ... ідеї?

Одна моя ідея полягала в тому, щоб звести до невеликого мініатюру, а потім випадковим чином вибрати 100 піксельних місць і порівняти.

Відповіді:


459

Нижче наведено три підходи до вирішення цієї проблеми (а їх є багато інших).

  • Перший - це стандартний підхід у комп’ютерному зорі, узгодження ключових точок. Це може зажадати деяких базових знань для впровадження, і це може бути повільно.

  • Другий метод використовує лише елементарну обробку зображення і потенційно швидший, ніж перший підхід, і його легко здійснити. Однак, що отримує зрозумілість, їй не вистачає надійності - збіг невдач на масштабованих, обернутих або знебарвлених зображеннях.

  • Третій метод є і швидким, і надійним, але потенційно найскладнішим у застосуванні.

Узгодження ключових точок

Краще ніж набрати 100 випадкових очок - це набрати 100 важливих очок. Окремі частини зображення мають більше інформації, ніж інші (особливо в краях та кутах), і це ті, які ви хочете використовувати для розумного зіставлення зображення. Google " вилучення ключових точок " та " відповідність ключових точок ", і ви знайдете досить багато наукових робіт з цього питання. Сьогодні ключові точки SIFT , мабуть, найпопулярніші, оскільки вони можуть відповідати зображенням під різними масштабами, обертаннями та освітленням. Деякі реалізації SIFT можна знайти тут .

Одним із недоліків відповідності ключових точок є час виконання наївної реалізації: O (n ^ 2m), де n - кількість ключових точок у кожному зображенні, а m - кількість зображень у базі даних. Деякі розумні алгоритми можуть швидше знайти найближчий збіг, як, наприклад, четвертинки або розбиття бінарного простору.


Альтернативне рішення: метод гістограми

Ще одним менш надійним, але потенційно швидшим рішенням є побудова функціональних гістограм для кожного зображення та вибір зображення за допомогою гістограми, найближчої до гістограми вхідного зображення. Я реалізував це як нижній рівень, і ми використовували 3 кольорові гістограми (червону, зелену та синю) та дві текстурні гістограми, напрямок та масштаб. Я наведу деталі нижче, але мушу зазначити, що це добре працювало лише для відповідності зображень ДУЖЕ подібних до зображень бази даних. За допомогою цього методу можна змінити масштабовані, повернені чи знебарвлені зображення, але невеликі зміни, такі як обрізання, не порушать алгоритм

Обчислення гістограм кольорів є простим - просто виберіть діапазон для своїх відер гістограм і для кожного діапазону підрахуйте кількість пікселів із кольором у цьому діапазоні. Наприклад, розглянемо "зелену" гістограму, і припустимо, що ми обираємо для своєї гістограми 4 відра: 0-63, 64-127, 128-191 та 192-255. Потім для кожного пікселя ми дивимось на зелене значення та додаємо підрахунок до відповідного відра. Коли ми закінчимо підрахунок, ділимо кожне відро на загальну кількість пікселів у всьому зображенні, щоб отримати нормалізовану гістограму для зеленого каналу.

Для гістограми напрямку текстури ми розпочали з виявлення краю на зображенні. Кожна крайова точка має нормальний вектор, що вказує в напрямку, перпендикулярному ребру. Ми квантували кут нормального вектора в одне з 6 відер між 0 і PI (оскільки краї мають 180-градусну симетрію, ми перетворили кути між -PI і 0 в 0 і PI). Після підрахунку кількості крайових точок у кожному напрямку, у нас є ненормована гістограма, що представляє напрямок текстури, яку ми нормалізували, розділивши кожне відро на загальну кількість крайових точок на зображенні.

Для обчислення гістограми шкали текстури для кожної крайової точки ми вимірювали відстань до наступної найближчої крайової точки з тим же напрямком. Наприклад, якщо точка ребра А має напрям 45 градусів, алгоритм рухається в тому напрямку, поки не знайде іншу крайню точку з напрямком 45 градусів (або в межах розумного відхилення). Обчисливши цю відстань для кожної крайової точки, ми скидаємо ці значення на гістограму та нормалізуємо її шляхом ділення на загальну кількість точок ребер.

Тепер у вас є 5 гістограм для кожного зображення. Для порівняння двох зображень ви берете абсолютне значення різниці між кожним відрізком гістограми, а потім підсумовуєте ці значення. Наприклад, для порівняння зображень A і B ми б обчислили

|A.green_histogram.bucket_1 - B.green_histogram.bucket_1| 

для кожного відра в зеленій гістограмі та повторіть для інших гістограм, а потім підведіть всі результати. Чим менший результат, тим краще матч. Повторіть усі зображення в базі даних, і збіг з найменшим результатом виграє. Напевно, ви хочете мати поріг, вище якого алгоритм робить висновок, що збігу не знайдено.


Третій вибір - ключові моменти + дерева рішень

Третій підхід, мабуть, набагато швидший, ніж інші два, - це використання семантичних текстонових лісів (PDF). Це включає вилучення простих ключових точок та використання дерев рішень колекції для класифікації зображення. Це швидше, ніж просте співставлення ключових точок SIFT, оскільки це дозволяє уникнути дорогого процесу узгодження, а ключові точки набагато простіші, ніж SIFT, тому вилучення ключових точок відбувається набагато швидше. Однак він зберігає інваріантність методу SIFT до обертання, масштабу та освітлення, важливої ​​особливості, якої не вистачало методу гістограми.

Оновлення :

Моя помилка - документ Semantic Texton Forests не стосується саме відповідності зображень, а мітки регіонів. Оригінальний документ, який відповідає цьому, є такий: Розпізнавання ключових точок за допомогою випадкових дерев . Крім того, статті нижче продовжують розвивати ідеї та представляють сучасний стан (c. 2010):


Здається, що підхід з гістограми має найбільше значення. Я припускаю, що ви можете повернути зображення, щоб виконати це з усіх боків на випадок, якщо зображення, яке порівнюється, було повернене (трактуючи таке ж зображення, як і 4) - спасибі
meade

4
@meade Це правильно. Ще щось, що слід врахувати: залежно від вашої проблеми, можливо, вам не знадобиться використовувати всі 5 гістограм у своєму алгоритмі. Якщо відхилити гістограму напрямку текстури, ви зможете відповідати оберненим версіям зображення. Відмова від гістограми шкали текстури дозволить вам зіставити повторно масштабовані версії зображення. Ви втратите певну здатність порівнювати подібність, але це може бути проблемою, залежно від вашої ситуації. Крім того, оскільки обчислення текстурної інформації є найдорожчою частиною алгоритму, це також зробить ваш алгоритм швидким.
Кайл Симек

@redmoskito: У мене питання. Як отримати числове значення, наприклад, гістограми зеленого кольору? Отже, ви можете відняти його за допомогою іншої гістограми зображення? Скажімо, у нас є зелена гістограма з 3 пікселями, що належать 0-63 відра, і 5 пікселів, що належать 64-127. Яке значення?
динамічний

3
@Ikaso, якщо це абсолютно однакове зображення, ви, ймовірно, не хочете використовувати щось подібне і розглянути можливість простого порівняння CRC або MD5. Якщо цього недостатньо, оскільки є окремі пікселі, які відрізняються або метадані змінилися, методу гістограми також достатньо. якщо ваші зображення однакові, але повернені чи масштабовані, метод, заснований на гістограмі, може бути достатнім, але, можливо, не вдасться. якщо ваші зображення змінили кольори, вам потрібно використовувати алгоритми на основі точок інтересу.
реокс

5
Хочеться додати, що на сьогоднішній день існує багато швидких альтернатив SIFT, таких як детектор FAST та бінарні дескриптори (BRIEF, BRISK, ORB, FREAK, BinBoost). Підручник з двійковими дескрипторами можна знайти тут: gilscvblog.wordpress.com/2013/08/26/…
GilLevi

85

Найкращий метод, про який я знаю, - це використовувати перцептивний хеш. Здається, хороша реалізація такого хешу з відкритим кодом доступна за адресою:

http://phash.org/

Основна ідея полягає в тому, що кожне зображення зводиться до невеликого хеш-коду або "відбитка пальця" шляхом ідентифікації яскравих особливостей у вихідному файлі зображення та хеш-компактного представлення цих функцій (а не хешування даних даних зображення). Це означає, що показник помилкових спрацьовувань значно зменшується за спрощеного підходу, наприклад, зменшення зображень до крихітного зображення розміру відбитків і порівняння відбитків пальців.

phash пропонує кілька типів хешу і може використовуватися для зображень, аудіо чи відео.


Хто цікавий у цьому методі, можна знайти реалізацію об'єктивного хешу Objective-C за посиланням github.com/ameingast/cocoaimagehashing
Олексій Войтенко

@AlexeyVoitenko Чи сумісний це з хешами, створеними phash.org у його конфігурації за замовчуванням?
Майкл

1
На мій досвід, phash добре працює для пошуку різних розмірів одного зображення, але не для подібних зображень. Наприклад, дві різні фотографії одного об’єкта можуть мати дуже різні хеші.
Рена

39

Ця публікація була відправною точкою мого рішення, тут багато хороших ідей, тому я хотів би поділитися своїми результатами. Основне розуміння полягає в тому, що я знайшов спосіб подолати повільність відповідності зображень на основі ключових точок, використовуючи швидкість фашу.

Для загального рішення найкраще використовувати кілька стратегій. Кожен алгоритм найкраще підходить для певних типів перетворень зображення, і ви можете цим скористатися.

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

  • файловий хеш (md5, sha1 тощо) для точних дублікатів
  • перцептивний хешинг (phash) для перетворених зображень
  • на основі функцій (SIFT) для модифікованих зображень

У мене дуже хороші результати з фашем. Точність хороша для масштабованих зображень. Це не добре для (сприйнятих) модифікованих зображень (обрізаних, повернутих, дзеркальних тощо). Для боротьби зі швидкістю хешування ми повинні використовувати кеш-диск / базу даних, щоб підтримувати хеші для стога сіна.

Дійсно про фаш - це те, що коли ви створюєте свою хеш-базу даних (яка для мене становить близько 1000 зображень / с), пошук може бути дуже-дуже швидким, зокрема, коли ви можете зберігати всю базу даних хешу в пам'яті. Це досить практично, оскільки хеш - лише 8 байт.

Наприклад, якщо у вас є 1 мільйон зображень, він потребує масиву в 1 мільйон 64-бітних хеш-значень (8 МБ). На деяких процесорах це вписується в кеш L2 / L3! У практичному використанні я бачив порівняння corei7 зі швидкістю понад 1 гіга-хам / сек, це лише питання пропускної здатності пам’яті до процесора. База даних на 1 мільярд зображень практична для 64-бітного процесора (потрібно 8 Гб оперативної пам’яті), а пошук не перевищує 1 секунди!

Для модифікованих / обрізаних зображень це може здатися детектором функцій / детекторів ключових точок, як SIFT. SIFT створить хороші ключові точки, які будуть виявляти обрізання / обертання / дзеркало тощо. Однак порівняння дескриптора дуже повільне порівняно з дистанцією забивання, яку використовує фаш. Це головне обмеження. Можна порівняти багато, оскільки є максимальний дескриптор IxJxK порівняння для пошуку одного зображення (I = кількість зображень сіна, J = цільові ключові точки на зображення стога сіна, K = цільові ключові точки на зображення голки).

Щоб вирішити проблему зі швидкістю, я спробував використати фаш навколо кожної знайденої ключової точки, використовуючи розмір / радіус функції, щоб визначити підпрямокутник. Трюк в тому, щоб зробити цю роботу добре, полягає в зростанні / зменшенні радіусу для створення різних рівнів під прямою стрілкою (на зображенні голки). Зазвичай перший рівень (без шкали) буде відповідати, але часто це займає ще кілька. Я не на 100% впевнений, чому це працює, але я можу уявити, що це дозволяє занадто малі функції, щоб фаш працював (фаш масштабує зображення до 32х32).

Інша проблема полягає в тому, що SIFT не буде розподіляти ключові точки оптимально. Якщо є ділянка зображення з великою кількістю ребер, то ключові точки будуть кластеризуватися там, і ви не отримаєте жодної в іншій області. Я використовую GridAdaptedFeatureDetector у OpenCV для покращення розповсюдження. Не впевнений, який розмір сітки найкращий, я використовую невелику сітку (1x3 або 3x1 залежно від орієнтації зображення).

Ймовірно, ви хочете масштабувати всі зображення сіна (і голки) до меншого розміру до виявлення функції (я використовую 210 пікселів уздовж максимального розміру). Це зменшить шум у зображенні (завжди це проблема алгоритмів комп'ютерного зору), а також сфокусує детектор на більш помітних функціях.

Для зображень людей ви можете спробувати розпізнавання облич і використовувати його для визначення розміру зображення в масштабі та розміру сітки (наприклад, найбільше обличчя з масштабністю 100 пікселів). Детектор функцій враховує кілька масштабних рівнів (використовуючи піраміди), але є обмеження на кількість рівнів, які він буде використовувати (це можна налаштувати, звичайно).

Детектор ключових точок, мабуть, працює найкраще, коли він повертає менше кількості бажаних функцій. Наприклад, якщо ви попросите 400 і повернете 300, це добре. Якщо ви отримуєте 400 назад кожен раз, ймовірно, якісь хороші функції потрібно було залишити.

Зображення голки може мати менше ключових точок, ніж зображення сіна, і все ж отримувати хороші результати. Якщо додати більше, не обов'язково ви отримаєте величезні прибутки, наприклад, J = 400 і K = 40, мій показник враження становить близько 92%. При J = 400 і K = 400 частота влучень піднімається лише до 96%.

Ми можемо скористатися надзвичайною швидкістю функції забивання, щоб вирішити масштабування, обертання, дзеркальне відображення тощо. Можна використовувати багатопрохідну техніку. На кожній ітерації перетворіть підпрямокутники, перекройте хеш і запустіть функцію пошуку знову.


8

Як зазначив Cartman, для пошуку точних дублікатів ви можете використовувати будь-яке хеш-значення.

Один вихідний пункт для пошуку близьких зображень може бути тут . Це інструмент, який використовуються компаніями CG, щоб перевірити, чи оновлені зображення все ще показують ту саму сцену.


7

У мене є ідея, яка може працювати, і це, швидше за все, буде дуже швидко. Ви можете піддіапробовувати зображення з роздільною здатністю 80x60 чи порівнянним, а також перетворити його в масштаб сірого (після підсистеми це буде швидше). Обробіть обидва зображення, які ви хочете порівняти. Потім запустіть нормовану суму різниць у квадраті між двома зображеннями (зображення запиту та кожне з db), або ще краще Normalized Cross Correlation, що дає відповідь ближче до 1, якщо обидва зображення схожі. Потім, якщо зображення схожі, ви можете перейти до більш складних прийомів, щоб переконатися, що це однакові зображення. Очевидно, що цей алгоритм є лінійним за кількістю зображень у вашій базі даних, тому навіть на 10000 зображень у секунду на сучасному апаратному забезпеченні буде дуже швидко. Якщо вам потрібна інваріантність обертання, то для цього невеликого зображення можна обчислити домінуючий градієнт, і тоді всю систему координат можна повернути до канонічної орієнтації, проте це буде повільніше. І ні, тут немає інваріантності масштабу.

Якщо ви хочете чогось більш загального або використовуєте великі бази даних (мільйон зображень), тоді вам потрібно вивчити теорію пошуку зображень (набір паперів з'явився за останні 5 років). В інших відповідях є вказівники. Але це може бути надмірним, і запропонований підхід гістограми зробить роботу. Хоча я думаю, що комбінація багатьох різних швидких підходів буде ще кращою.


7

У моїй компанії близько 24 мільйонів зображень надходять від виробників щомісяця. Я шукав швидке рішення, щоб гарантувати, що зображення, які ми завантажуємо в наш каталог, є новими зображеннями.

Хочу сказати, що я шукав в Інтернеті далеко і широко, щоб спробувати знайти ідеальне рішення. Я навіть розробив власний алгоритм виявлення краю.
Я оцінив швидкість і точність декількох моделей. Мої зображення, які мають білий фон, надзвичайно добре працюють із фашированием. Як сказав redcalx , я рекомендую phash або ahash. НЕ використовуйте MD5 Hashing або будь-які інші криптографічні хеші. Якщо ви не хочете, щоб відповідати саме ТОЧНІ зображення. Будь-яке зміна розміру або маніпуляції між зображеннями дасть різний хеш.

Для phash / ahash, перевірте це: imagehash

Я хотів продовжити повідомлення * redcalx *, розмістивши свій код та мою точність.

Що я роблю:

from PIL import Image
from PIL import ImageFilter
import imagehash

img1=Image.open(r"C:\yourlocation")
img2=Image.open(r"C:\yourlocation")
if img1.width<img2.width:
    img2=img2.resize((img1.width,img1.height))
else:
    img1=img1.resize((img2.width,img2.height))
img1=img1.filter(ImageFilter.BoxBlur(radius=3))
img2=img2.filter(ImageFilter.BoxBlur(radius=3))
phashvalue=imagehash.phash(img1)-imagehash.phash(img2)
ahashvalue=imagehash.average_hash(img1)-imagehash.average_hash(img2)
totalaccuracy=phashvalue+ahashvalue

Ось деякі мої результати:

item1  item2  totalsimilarity
desk1  desk1       3
desk1  phone1     22
chair1 desk1      17
phone1 chair1     34

Сподіваюся, це допомагає!


6

Я вважаю, що зменшити розмір зображення до майже розміру значка, скажімо, 48x48, потім перетворитись у масштаб сірого, а потім взяти різницю між пікселями чи Delta, має працювати добре. Оскільки ми порівнюємо зміну кольору пікселів, а не фактичного кольору пікселів, не має значення, чи зображення трохи світліше або темніше. Великі зміни будуть мати значення, оскільки пікселі, які надто світлі / темні, будуть втрачені. Ви можете застосувати це в одному ряду або скільки завгодно, щоб підвищити точність. Щонайбільше у вас слід зробити віднімання 47x47 = 2 210, щоб сформувати порівнянний ключ.


3

Вибір 100 випадкових очок може означати, що подібні (а іноді навіть різні) зображення будуть позначені як однакові, що, я вважаю, є не тим, що ви хочете. Хеші MD5 не працюватимуть, якби зображення були різного формату (png, jpeg тощо), мали різний розмір або мали різні метадані. Зменшення всіх зображень на менший розмір - хороша ставка, порівняння пікселів за пікселем не повинно займати занадто довго, доки ви використовуєте хорошу бібліотеку зображень / швидку мову, а розмір досить малий.

Ви можете спробувати зробити їх крихітними, тоді якщо вони однакові, виконайте ще одне порівняння на більші розміри - це може бути гарним поєднанням швидкості та точності ...


Якщо ви шукаєте точні дублікати, але з різними форматами / метаданими, ви можете робити хеш (наприклад, MD5) фактичних значень пікселів. Imagemagick називає це підписом (не пов’язаним із криптографічним підписом). Ви також можете спочатку зменшити її, наприклад, обрізання до 4 біт на піксель, щоб зменшити вплив артефактів JPEG, або перетворити в масштаб сірого, щоб відповідати трохи перефарбованим зображенням.
Рена

2

Якщо у вас є велика кількість зображень, подивіться у фільтр Bloom , який використовує кілька хешей для імовірнісного, але ефективного результату. Якщо кількість зображень не величезна, то криптографічного хеша на зразок md5 повинно бути достатньо.


Отже (намагаючись зрозуміти фільтр Bloom) - це означає, що ви вибираєте випадкові піксельні точки на базовому зображенні, випадково отримуєте або червоне / зелене / синє значення пікселя - тоді порівнюєте з новим зображенням? а потім скористайтеся рівнем ймовірності (збіг 90%), щоб визначити, наскільки подібні два зображення?
meade

5
Це не перевірка подібності, це перевірка еквівалентності. Якщо вам потрібна схожість, то хешування - це не правильний підхід. Ідея Bloom полягає у використанні декількох хеш-алгоритмів, щоб збільшити ймовірність унікальної ідентифікації. Вибір випадкових точок - не найкращий підхід для алгоритму хешування, тому що він даватиме різні результати щоразу.
jdigital
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.