То, что происходит в вашем коде, довольно просто объяснить:
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 градусов.
Вместо этого вы должны вычислить величину и порог (я не знаю, является ли Оцу идеальным методом для такого изображения).Далее, используйте только угол для тех пикселей, где величина выше порогового значения.
Другая распространенная альтернатива - использование гауссовых градиентов вместо Собеля.Там вы можете установить параметр сглаживания (регуляризации), который позволяет удалять больше или меньше шума.Я часто вижу, что это реализовано как размытие по Гауссу, за которым следуют фильтры Собеля, хотя для меня более логично использовать фильтры производных по Гауссу.