Як я можу виявити, що два зображення є "однаковими", навіть якщо на одному є трохи різний показник обрізання / співвідношення?


11

У мене є два різних зображення:

в 100 пікселів з введіть тут опис зображенняабо 400 піксвведіть тут опис зображення

і

в ширину 100 введіть тут опис зображенняпікселів або 400 піксвведіть тут опис зображення

Як ви бачите, ці два чітко "однакові" з людської точки зору. Тепер я хочу програмно виявити, що вони однакові. Я використовую магію зображень через дорогоцінний камінь, який називається rmagickтак:

img1 = Magick::Image.from_blob(File.read("image_1.jpeg")).first
img2 = Magick::Image.from_blob(File.read("image_2.jpeg")).first

if img1.difference(img2).first < 4000.0 # I have found this to be a good threshold, but does not work for cropped images
  puts "they are the same!!!"
end

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

Чи є спосіб зробити це для зображень з різним обрізанням? Мене цікавить рішення, де я можу сказати щось на кшталт: одне зображення міститься всередині іншого і охоплює десь близько 90% його.

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


2
Не впевнений у RMagick, але compareінструмент командного рядка ImageMagick має -subimage-searchкомутатор.
Стефан

Це цікаво, як би виглядала така команда?
Нільс Крістіан

2
Ніколи не використовував його сам, можливо, це допомагає: stackoverflow.com/q/29062811/477037
Стефан

Дякую, це чудова інформація. Я не можу зрозуміти, як це зробити з рубіну ...
Нільс Крістіан,

1
Чи є зображення неякісними? Якщо ні, будь ласка, поділіться більшою версією зображень з більшою якістю.
MH304

Відповіді:


6

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

З огляду на два надані зображення, ось спроба зіставити функції за допомогою відповідника функцій FLANN . Щоб визначити, чи однакові два зображення, ми можемо базувати його на певному заздалегідь визначеному порозі, який відстежує кількість збігів, які проходять тест на співвідношення, описаний у розділі Особливості зображення від масштабних інваріантних ключових точок Девід Г. Лоу . Просте пояснення тесту полягає в тому, що тест на співвідношення перевіряє, чи збіги неоднозначні і їх слід вилучити, ви можете трактувати це як техніку видалення сторонніх людей. Ми можемо порахувати кількість збігів, які пройшли цей тест, щоб визначити, чи однакові два зображення. Ось результати відповідності функції:

Matches: 42

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


Я реалізував це в Python, я не дуже знайомий з Rails. Сподіваюся, це допомагає, удачі!

Код

import numpy as np
import cv2

# Load images
image1 = cv2.imread('1.jpg', 0)
image2 = cv2.imread('2.jpg', 0)

# Create the sift object
sift = cv2.xfeatures2d.SIFT_create(700)

# Find keypoints and descriptors directly
kp1, des1 = sift.detectAndCompute(image2, None)
kp2, des2 = sift.detectAndCompute(image1, None)

# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary
flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]

count = 0
# Ratio test as per Lowe's paper (0.7)
# Modify to change threshold 
for i,(m,n) in enumerate(matches):
    if m.distance < 0.15*n.distance:
        count += 1
        matchesMask[i]=[1,0]

# Draw lines
draw_params = dict(matchColor = (0,255,0),
                   # singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

# Display the matches
result = cv2.drawMatchesKnn(image2,kp1,image1,kp2,matches,None,**draw_params)
print('Matches:', count)
cv2.imshow('result', result)
cv2.waitKey()

2
Супер цікавий підхід, я підкажу і повернусь ...
Нільс Крістіан

PS. Я оновив зображення в більшому масштабі
Нільс Крістіан

1
@nathancy Це так, що у вашому прикладі зелені крапки відповідають, а сині ні? Схоже, є занадто багато незрівнянних точок?
Драко Атер

2
@DracoAter Добре запитання, блакитні точки представляють усі матчі, тоді як ми проводимо лише "хороші відповідники", які проходять тест на співвідношення зеленого кольору. Якщо ви не використовуєте тест на відношення, то всі бали будуть виведені, але ми фільтруємо за допомогою тесту на відношення, щоб намалювати «кращі» відповідники. Таким чином, ОП може використовувати цей тест як поріг, щоб зберегти лише найкращі відповідні функції. Отже, всі блакитні точки - це функції, які знайшов SIFT, але ми фільтруємо, щоб зберегти хороші, які намальовані зеленим кольором
nathancy

Дякую. конкуренція була складною на відповіді, багато чудових :-)
Нільс Крістіан

4

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

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

require 'open3'

def check_subimage(large, small)
    stdin, stdout, stderr, wait_thr = Open3.popen3("magick compare -subimage-search -metric RMSE #{large} #{small} temp.jpg")
    result = stderr.gets
    stderr.close
    stdout.close
    return result.split[1][1..-2].to_f < 0.2
end

if check_subimage('a.jpg', 'b.jpg')
    puts "b is a crop of a"
else
    puts "b is not a crop of a"
end

Я висвітлю важливі речі, а потім розповім про додаткові замітки.

Команда використовує магічне порівняння, щоб перевірити, чи друге зображення ( small) є підримом першого ( large). Ця функція не перевіряє, що мале строго менше, ніж велике (і висота, і ширина). Число, яке я поставив для подібності, становить 0,2 (20% помилка), а значення для наданих вами зображень - приблизно 0,15. Ви можете налаштувати це! Я вважаю, що зображення, які є суворим підмножиною, отримують менше 0,01.

  • Якщо ви хочете менше помилок (менших цифр) у випадках, коли у вас 90% перекриття, але друге зображення має деякі додаткові речі, перше - ні, ви можете запустити його один раз, а потім обріжте перше велике зображення туди, де міститься підрозмір , потім запустіть його знову з обрізаним зображенням як "малим" та оригінальним "малим" зображенням як великим.
  • Якщо ви дійсно хотіли приємного об'єктно-орієнтованого інтерфейсу в Ruby, rmagick використовує API MagicCore. Ця команда (посилання на документи) - це, мабуть, те, що ви хочете використовувати для її реалізації, і ви можете відкрити pr до rmagick або пакувати cext самостійно.
  • Використання open3 запустить потік ( див. Документи ). Закриття stderrі stdoutне є «необхідним» , але ви повинні.
  • Образ "temp", який є третім аргументом, визначає файл для виведення аналізу на. Швидким поглядом я не зміг знайти спосіб не вимагати цього, але він просто перезаписується автоматично, і це може бути непогано зберегти для налагодження. Для вашого прикладу це виглядатиме так;

введіть тут опис зображення

  • Повний вихід у форматі 10092,6 (0,154003) @ 0,31. Перше число - це значення rmse з 655535, друге (яке я використовую) - це нормалізований відсоток. Останні два числа відображають розташування вихідного зображення, з якого починається невелике зображення.
  • Оскільки немає об’єктивного джерела істини щодо того, наскільки "подібні" зображення, я вибрав RMSE (див. Більше метричних варіантів тут ). Це досить поширена міра відмінностей між значеннями. Абсолютна кількість помилок (AE) може здатися хорошою ідеєю, однак, здається, що програмне забезпечення для обрізання не ідеально зберігає пікселі, тому вам, можливо, доведеться відрегулювати нечітке значення і це не нормалізоване значення, тож вам доведеться порівняти кількість помилок з розміром зображення і тим більше.

1
Ось якась справді чудова інформація, Керол. Спасибі
Нільс Крістіан

Цікаво дізнатися, як це працює для інших ваших справ!
Керрол Чен

1
Дякую за супер чудову відповідь. Якби я міг, я тобі дав би і нагороду в розмірі 100 пунктів :-)
Нільс Крістіан,

3

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

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


Дякую за пораду, я погляну на це.
Нільс Крістіан

Це не дуже корисна відповідь, оскільки не демонструє, як досягти мети. Це еквівалент "Google цим терміном і придумайте самі".
Anothermh

Гістограма - одне з перших речей, які люди вивчають при обробці зображень. Якщо комусь доведеться погуглити його, то я дуже вибачаюся.
Raviteja Narra

3

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

У opencv, використовуючи метод TM_CCOEFF_NORMED , дає оцінку між 0 і 1. Якщо оцінка дорівнює 1, це означає, що шаблон шаблону є точно частиною (Rect) вихідного зображення, але якщо у вас є невелика зміна освітлення або перспективи між два зображення, оцінка буде нижчою за 1.

Тепер, розглядаючи поріг для оцінки схожості, ви можете дізнатися, чи вони однакові чи ні. Цей поріг можна отримати шляхом проб і помилок на кількох зразкових зображеннях. Я спробував ваші образи і отримав оцінку 0,823863 . Ось код (opencv C ++) та спільна область між двома зображеннями, отримана шляхом відповідності:

введіть тут опис зображення

Mat im2 = imread("E:/1/1.jpg", 1);
//Mat im2;// = imread("E:/1/1.jpg", 1);
Mat im1 = imread("E:/1/2.jpg", 1);

//im1(Rect(0, 0, im1.cols - 5, im1.rows - 5)).copyTo(im2);

int result_cols = im1.cols - im2.cols + 1;
int result_rows = im1.rows - im2.rows + 1;

Mat result = Mat::zeros(result_rows, result_cols, CV_32FC1);

matchTemplate(im1, im2, result, TM_CCOEFF_NORMED);

double minVal; double maxVal;
Point minLoc; Point maxLoc;
Point matchLoc;

minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

cout << minVal << " " << maxVal << " " << minLoc << " " << maxLoc << "\n";
matchLoc = maxLoc;

rectangle(im1, matchLoc, Point(matchLoc.x + im2.cols, matchLoc.y + im2.rows), Scalar::all(0), 2, 8, 0);
rectangle(result, matchLoc, Point(matchLoc.x + im2.cols, matchLoc.y + im2.rows), Scalar::all(0), 2, 8, 0);

imshow("1", im1);
imshow("2", result);
waitKey(0);

Дякую за супер чудову відповідь. Якби я міг, я тобі дав би і нагороду в розмірі 100 пунктів :-)
Нільс Крістіан,

2

Розглянемо метод find_s similar_region . Використовуйте менший з двох зображень як цільове зображення. Спробуйте різні значення атрибутів нечіткості на зображенні та цільовому зображенні.


Дякую, проте я не можу змусити його працювати - ви можете?
Нільс Крістіан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.