Нахождение изображения внутри изображения Numpy - PullRequest
16 голосов
/ 06 октября 2011

У меня есть два массива 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)

position будет тогда (0, 2).

Ответы [ 4 ]

31 голосов
/ 13 февраля 2012

Я делаю это с помощью функции OpenCV matchTemplate . Существует отличная привязка Python к OpenCV, которая использует numpy внутри, поэтому изображения - это просто numy массивы. Например, предположим, у вас есть BGR-файл размером 100x100 пикселей testimage.bmp . Мы берем 10x10 субизображение в позиции (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, каждый из которых является совпадающей координатой.

8 голосов
/ 08 октября 2011

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

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

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

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

2 голосов
/ 15 февраля 2015

Вы можете фактически свести эту проблему к простому поиску строк, используя 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)
2 голосов
/ 04 сентября 2012

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

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

...