Поиск субимажа внутри изображения Numpy

У меня есть два массива Numpy (3-мерный uint8), преобразованный из изображений PIL.

Я хочу найти, если первое изображение содержит второе изображение, и если да, то найдите координаты верхнего левого пикселя внутри первого изображения, где находится совпадение.

Есть ли способ сделать это чисто в Numpy, достаточно быстро, вместо того, чтобы использовать (4! Очень медленные) чистые петли Python?

Пример 2D:

a = numpy.array([ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11] ]) b = numpy.array([ [2, 3], [6, 7] ]) 

Как это сделать?

 position = a.find(b) 

тогда будет положение (0, 2) .

4 Solutions collect form web for “Поиск субимажа внутри изображения Numpy”

Это можно сделать, используя scipy's коррелят2d, а затем используя argmax, чтобы найти пик в кросс-корреляции.

Вот более полное объяснение математики и идей, а также некоторые примеры.

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

Редактировать: на вопрос задан особый вопрос о чистом решении «Нюми» . Но если вы можете использовать OpenCV или другие инструменты обработки изображений, очевидно, что проще использовать один из них. Примером такого является приведенный ниже PiQuer, который я бы рекомендовал, если вы можете его использовать.

Я делаю это с matchTemplate функции matchTemplate OpenCV . Существует превосходная привязка к python для OpenCV, которая использует numpy внутри, поэтому изображения представляют собой просто массивы с несколькими числами. Например, предположим, что у вас есть файл BGR размером 100×100 пикселей testimage.bmp . Мы берем суб-изображение 10×10 в позиции (30,30) и находим его в оригинале.

 import cv2 import numpy as np image = cv2.imread("testimage.bmp") template = image[30:40,30:40,:] result = cv2.matchTemplate(image,template,cv2.TM_CCOEFF_NORMED) print np.unravel_index(result.argmax(),result.shape) 

Вывод:

 (30, 30) 

Вы можете выбирать между несколькими алгоритмами, чтобы соответствовать шаблону оригиналу, cv2.TM_CCOEFF_NORMED – это только один из них. Более подробную информацию см. В документации, некоторые алгоритмы указывают совпадения как минимумы, другие – как максимумы в массиве результатов. Предупреждение: OpenCV по умолчанию использует порядок каналов BGR, поэтому будьте осторожны, например, когда вы сравниваете изображение, загруженное cv2.imread на изображение, которое вы преобразовали из PIL в numpy. Вы всегда можете использовать cv2.cvtColor для преобразования между форматами.

Чтобы найти все совпадения выше заданной пороговой confidence , я использую что-то в этом направлении, чтобы извлечь согласованные координаты из массива результатов:

 match_indices = np.arange(result.size)[(result>confidence).flatten()] np.unravel_index(match_indices,result.shape) 

Это дает кортеж массивов длиной 2, каждый из которых является совпадающей координатой.

Я только что закончил писать автономную реализацию нормированной кросс-корреляции для N-мерных массивов. Вы можете получить это отсюда .

Кросс-корреляция рассчитывается либо напрямую, используя scipy.ndimage.correlate , либо в частотной области, используя scipy.fftpack.fftn / ifftn зависимости от того, что будет быстрее для данных размеров ввода.

Фактически вы можете уменьшить эту проблему до простого поиска строк, используя regex подобное следующей реализации, – принимает два объекта PIL.Image и находит координаты needle в haystack . Это примерно на 127 раз быстрее, чем использование поэтапного поиска.

 def subimg_location(haystack, needle): haystack = haystack.convert('RGB') needle = needle.convert('RGB') haystack_str = haystack.tostring() needle_str = needle.tostring() gap_size = (haystack.size[0] - needle.size[0]) * 3 gap_regex = '.{' + str(gap_size) + '}' # Split b into needle.size[0] chunks chunk_size = needle.size[0] * 3 split = [needle_str[i:i+chunk_size] for i in range(0, len(needle_str), chunk_size)] # Build regex regex = re.escape(split[0]) for i in xrange(1, len(split)): regex += gap_regex + re.escape(split[i]) p = re.compile(regex) m = p.search(haystack_str) if not m: return None x, _ = m.span() left = x % (haystack.size[0] * 3) / 3 top = x / haystack.size[0] / 3 return (left, top) 
  • Как открыть изображение из Интернета в PIL?
  • Метод getbbox из библиотеки изображений python (PIL) не работает
  • Как получить формат изображения с PIL?
  • Установка PIL для использования с Django в Mac OS X
  • Перевести Exif DMS на DD Geolocation с помощью Python
  • Как использовать PIL для изменения размера и применения данных EXIF ​​в файл?
  • Tkinter & PIL Изменить размер изображения на этикетке
  • Использование Pycairo для генерации изображений динамически и обслуживания в Django
  • Python - лучший язык программирования в мире.