Быстрый метод перекрестной корреляции в Python
недавно я пытался найти быстрый и эффективный способ выполнения перекрестной проверки корреляции между двумя массивами с использованием языка Python. После некоторого чтения я нашел эти два варианта:
- The
NumPy.correlate()
метод, который слишком медленный, когда дело доходит до больших массивов. - The
cv.MatchTemplate()
метод, который, кажется, гораздо быстрее.
по понятным причинам, я выбрал второй вариант. Я попытался выполнить следующее код:
import scipy
import cv
image = cv.fromarray(scipy.float32(scipy.asarray([1,2,2,1])),allowND=True)
template = cv.fromarray(scipy.float32(scipy.asarray([2,2])),allowND=True)
result = cv.fromarray(scipy.float32(scipy.asarray([0,0,0])),allowND=True)
cv.MatchTemplate(image,template,result,cv.CV_TM_CCORR)
даже если этот код должен быть очень простым, он выдает следующую ошибку:
OpenCV Error: Bad flag (parameter or structure field) (Unrecognized or unsupported array type) in cvGetMat, file /builddir/build/BUILD/OpenCV-2.1.0/src/cxcore/cxarray.cpp, line 2476
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cv.error: Unrecognized or unsupported array type
после нескольких часов разочаровывающих попыток я все еще застрял! У кого-нибудь есть предложения?
кстати, это моя версия Python:
Python 2.7 (r27:82500, Sep 16 2010, 18:03:06)
[GCC 4.5.1 20100907 (Red Hat 4.5.1-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
спасибо всем!
2 ответов
вы вряд ли получите намного быстрее, чем с помощью метода корреляции на основе fft.
import numpy
from scipy import signal
data_length = 8192
a = numpy.random.randn(data_length)
b = numpy.zeros(data_length * 2)
b[data_length/2:data_length/2+data_length] = a # This works for data_length being even
# Do an array flipped convolution, which is a correlation.
c = signal.fftconvolve(b, a[::-1], mode='valid')
# Use numpy.correlate for comparison
d = numpy.correlate(a, a, mode='same')
# c will be exactly the same as d, except for the last sample (which
# completes the symmetry)
numpy.allclose(c[:-1], d) # Should be True
Теперь для сравнения времени:
In [12]: timeit b[data_length/2:data_length/2+data_length] = a; c = signal.fftconvolve(b, a[::-1], mode='valid')
100 loops, best of 3: 4.67 ms per loop
In [13]: timeit d = numpy.correlate(a, a, mode='same')
10 loops, best of 3: 69.9 ms per loop
Если вы можете справиться с круговой корреляцией, вы можете удалить копию. Разница во времени будет увеличиваться, как data_length
увеличивается.
Я считаю, что ваш код терпит неудачу, потому что OpenCV ожидает изображения в формате uint8, а не float32. Вы можете найти интерфейс CV2 python более интуитивно понятным в использовании (автоматическое преобразование между форматами изображений ndarray и CV).
Что касается скорости корреляции, вы можете попробовать использовать быструю реализацию fft (FFTW имеет оболочку python:pyfftw).