OpenCV filter2d дает неверный результат - PullRequest
0 голосов
/ 19 февраля 2019

В настоящее время я пытаюсь отфильтровать изображение с помощью лапласианского ядра, которое я создал сам.Однако при фильтрации входного изображения с помощью этого ядра это дает неожиданный результат по сравнению с реализацией в SciPy.

Ядро лапласиана, которое я построил, должно быть подтверждено следующими изображениями

1D2D

Код для фильтрации изображения:

im = cv2.imread("test.png",0)
im = im.astype(np.float32)

def lkern(t=1.):
    ax = np.arange(np.round(-5*np.sqrt(t),0),np.round(5*np.sqrt(t),0)+1)
    xx, yy = np.meshgrid(ax, ax)

    kernel = -1/(np.sqrt(2*np.pi*t)*t)*np.exp(-(xx**2+yy**2)/(2*t))+
        (xx**2+yy**2)/(np.sqrt(2*np.pi*t)*t**2)*np.exp(-(xx**2+yy**2)/(2*t))


    return kernel.astype(np.float)

t = 25**2/2
l = lkern(t)

L = cv2.filter2D(im/255,-1,l)

plt.figure()
plt.imshow(L,cmap="gray")
plt.show()

, что приводит к

res

По сравнению с ndimage.gaussian_laplace SciPy's,результат должен был быть

scipy

, который сильно отличается, и я не могу понять, как это сделать правильно.

1 Ответ

0 голосов
/ 19 февраля 2019

Код в ОП, кажется, берет уравнение для одномерного Лапласа Гаусса и использует его для построения двумерной радиально-симметричной функции.То есть, вдоль любого диаметра ядра функция выглядит как одномерная лапласа Гаусса.Это неправильный способ создания двумерной лапласа Гаусса.

Лаплас Гаусса определяется как как сумма производной второго порядка гауссова ядра по каждой из осей.То есть

LoG = d²/dx² G + d²/dy² G

С G ядром Гаусса.

С Numpy вы можете построить это ядро ​​следующим образом.Я использую гауссову отделимость для уменьшения сложности вычислений.

s = 5;
x = np.arange(np.floor(-4*s),np.ceil(4*s)+1)
g = 1/(np.sqrt(2*np.pi)*s)*np.exp(-x**2/(2*s**2))
d2g = (x**2 - s**2)/(s**4) * g
log = g * d2g[:,None] + g[:,None] * d2g

Трюки здесь: g и d2g являются одномерными функциями.g[:,None] поворачивает 1D функцию на бок, так что умножение вызывает широковещательную передачу, что приводит к 2D-выводу.

Я написал ядро ​​таким образом, а не выражал полное 2D-уравнение за один раз, потому чтоэто приводит к большой эффективности в вашем коде: свертка изображения f с ядром log может быть записана как:

conv(f, log) = conv(f, g * d2g[:,None] + g[:,None] * d2g)
             = conv(conv(f, g), d2g[:,None]) + conv(conv(f, g[:,None]), d2g)

, то есть вместо одной свертки с большим двумерным ядром,мы вычисляем 4 свертки с относительно маленькими одномерными ядрами.Обратите внимание, что фактический порядок здесь не имеет значения:

  • Один применяет одномерное ядро ​​g, а в результате 1D-ядро d2g вдоль другой оси.Эти две операции можно повернуть вспять.
  • Затем один повторяет этот процесс, изменяя оси, к которым применяется каждая из операций.
  • Наконец, один добавляет два результата.

(Можно использовать cv2.filter2D там, где я написал conv. conv просто указывает на любую функцию свертки, но корреляционная функция, такая как filter2D, подходит, потому что все ядра симметричны.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...