Otsu Thresholding и ориентация градиента изображения - PullRequest
0 голосов
/ 29 сентября 2018

Я хочу применить пороговое значение Otsu для градиентов изображения (для удаления шума).После этого я хочу вычислить ориентацию градиентов.К сожалению, когда я это делаю, я получаю ориентацию градиента только от 0 до 90 градусов.Без порогового значения Otsu значения находятся в диапазоне от 0 до 360.

См. Мой код на Python

import numpy as np
import cv2

img = cv2.imread('Ob.png',cv2.IMREAD_GRAYSCALE)
img = img.astype('float32')
img2 = 
dst1 = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
dst2 = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)

ret1,th1 = cv2.threshold(dst1.astype(np.uint8),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
ret2,th2 = cv2.threshold(dst2.astype(np.uint8),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

mag, ang = cv2.cartToPolar(dst1.astype(np.float32),dst2.astype(np.float32))
np.rad2deg(ang)

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

То, что происходит в вашем коде, довольно просто объяснить:

dst1 и dst2, выходные данные двух фильтров Собеля, являются компонентами x и y вектора градиента.Для одного данного пикселя вектор градиента задается как (dst1[i,j], dst2[i,j]).Этот вектор может иметь любые значения, например (5.8, -2.1), что приводит к углу около 340 градусов.

Далее вы пороговаете эти два изображения.Otsu thresholding найдет значение, для которого изображение будет красиво разделено на пиксели низкой интенсивности и пиксели высокой интенсивности.Им присвоены значения 0 и 255 соответственно.Но сначала вы конвертируете изображения с плавающей точкой в ​​uint8, устанавливая все отрицательные значения в 0. Итак, наш вектор (5.8, -2.1) сначала преобразуется в (5,0), а затем в пороговое значение, после чего он становится либо (255,0) или (0,0) в зависимости от того, на какую сторону порога падает цифра 5.

Таким образом, мы преобразовали вектор с углом 340 градусов в единицу с углом 0 градусов или нетвычисляемый угол (хотя atan2(0,0) обычно также дает 0).

Фактически все векторы стали либо (0,0), (0,255), (255,0), либо (255,255), что означает, что вынайдет только углы 0, 45 и 90 градусов.

Вместо этого вы должны вычислить величину и порог (я не знаю, является ли Оцу идеальным методом для такого изображения).Далее, используйте только угол для тех пикселей, где величина выше порогового значения.

Другая распространенная альтернатива - использование гауссовых градиентов вместо Собеля.Там вы можете установить параметр сглаживания (регуляризации), который позволяет удалять больше или меньше шума.Я часто вижу, что это реализовано как размытие по Гауссу, за которым следуют фильтры Собеля, хотя для меня более логично использовать фильтры производных по Гауссу.

0 голосов
/ 30 сентября 2018

Если я могу, почему первое, что вы делаете, это конвертируете данные в float32?

Я думаю, что было бы более эффективно просто позволить это сделать во время обработки Sobel.Это только моя точка зрения.

То, что вы назвали "шумом" в результате градиентного фильтра, на самом деле называется не максимумами.Часто такой алгоритм, как Canny, состоит в том, что он пороговый после фильтрации Sobel .Неудобно при таком подходе находить соответствующие пороги.Лично я использую немахимическое подавление другого алгоритма.

Ваш код станет:

import numpy as np
import cv2

img = cv2.imread('Ob.png',cv2.IMREAD_GRAYSCALE)

dx,dy = cv2.spatialGradient(img,ksize=5)

mag = cv2.magnitude(dx.astype(np.float32),dy.astype(np.float32))

se = cv2.ximgproc_StructuredEdgeDetection()

ori = se.computeOrientation(mag)

edges_without_nms = se.edgesNms(mag,ori)

Надеюсь, он вам поможет.

...