Интерпретация Собеля из cv2 - PullRequest
0 голосов
/ 04 июля 2018

Я пытаюсь понять свертку Собеля из cv2 в Python.

Согласно документации ядро ​​Собеля

-1 0 1
-2 0 2
-1 0 1

Итак, я попытался применить его к следующему img (двоичный массив 3x3):

0 1 0
1 0 1
0 1 0

Теперь у меня проблема с интерпретацией выходных данных. Я вычислил вручную и получил другой результат. Насколько я знаю, я должен центрировать ядро ​​в каждом пикселе (i,j) и умножать его на элементы и суммы.

Итак, первая запись в выводе должна быть 2. Программа возвращает 0.

Я не прав? Я надеюсь на это.

Код

import cv2
import numpy as np

img = np.array([[0,1,0],[1,0,1],[0,1,0]]).astype(float)

# Output dtype = cv2.CV_8U
sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=3)

# Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)

abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)

print 'img'
print img

print 'sobelx8u'
print sobelx8u

print 'sobelx64f'
print sobelx64f

print 'abs_sobel64f'
print abs_sobel64f

print 'sobel_8u'
print sobel_8u

выход

img
[[ 0.  1.  0.]
 [ 1.  0.  1.]
 [ 0.  1.  0.]]
sobelx8u
[[0 0 0]
 [0 0 0]
 [0 0 0]]
sobelx64f
[[ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 0.  0.  0.]]
abs_sobel64f
[[ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 0.  0.  0.]]
sobel_8u
[[0 0 0]
 [0 0 0]
 [0 0 0]]

1 Ответ

0 голосов
/ 06 июля 2018

Прочтите второй абзац вашей документации страницы:

Другая общая особенность функций и классов, описанных в этом разделе, заключается в том, что, в отличие от простых арифметических функций, им необходимо экстраполировать значения некоторых несуществующих пикселей. Например, если вы хотите сгладить изображение с использованием фильтра Гаусса 3x3, то при обработке крайних левых пикселей в каждой строке вам понадобятся пиксели слева от них, то есть за пределами изображения. Вы можете сделать так, чтобы эти пиксели были такими же, как крайние левые пиксели изображения (метод экстраполяции с «реплицированной границей»), или предположить, что все несуществующие пиксели являются нулями (метод экстраполяции с «постоянной границей»), и так далее. OpenCV позволяет вам указать метод экстраполяции. Подробнее см. Функцию borderInterpolate() и обсуждение параметра borderType в разделе и различные функции ниже.

Сделайте так, как вы ожидали

Чтобы он работал так, как вы ожидали, он должен был явно указать, что вы хотите интерполировать вашу границу с нулевыми значениями. Как это:

import cv2
import numpy as np

img = np.array([[0,1,0],[1,0,1],[0,1,0]]).astype(float)

border = cv2.borderInterpolate(0, 1, cv2.BORDER_CONSTANT)
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3, borderType=border)

print 'img'
print img

print 'sobelx64f'
print sobelx64f

Выход:

img
[[ 0.  1.  0.]
 [ 1.  0.  1.]
 [ 0.  1.  0.]]
sobelx64f
[[ 2.  0. -2.]
 [ 2.  0. -2.]
 [ 2.  0. -2.]]

Тип границы по умолчанию

Значение по умолчанию borderType равно BORDER_DEFAULT, что на моей машине такое же, как BORDER_REFLECT_101. Вы можете запустить этот скрипт, чтобы подтвердить его на своем компьютере:

import cv2

for var in dir(cv2):
    if not var.startswith('BORDER_'): continue
    if cv2.__dict__[var] == cv2.BORDER_DEFAULT:
        print 'BORDER_DEFAULT ==', var

Выход:

BORDER_DEFAULT == BORDER_DEFAULT
BORDER_DEFAULT == BORDER_REFLECT101
BORDER_DEFAULT == BORDER_REFLECT_101

И BORDER_REFLECT_101 работает именно так, как это соответствует вашим результатам. Вот объяснение различных типов границ:

BORDER_REPLICATE:     aaaaaa|abcdefgh|hhhhhhh
BORDER_REFLECT:       fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101:   gfedcb|abcdefgh|gfedcba
BORDER_WRAP:          cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii  with some specified 'i'

Объяснение того, что вы получаете

Таким образом, тип интерполяции границ по умолчанию (равный BORDER_REFLECT_101) делает ваш массив таким, каким он был до вычисления:

0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0

С помощью простой арифметики вы можете подтвердить, что правильные значения после применения ядра Собеля к внутренним пикселям 3x3 - все нули - это то, что вы получили, запустив свой скрипт.

...