градиент изображения
Градиент изображения вычисляет скорость изменения изображения. Для краевой части изображения значение серого изменяется сильно, и значение градиента также велико, и, наоборот, для относительно гладкой части изображения значение серого изменяется меньше, и соответствующее значение градиента также мало. Как правило, вычисление градиента изображения представляет собой информацию о границах изображения.
На самом деле градиент является производной, но градиент изображения обычно получает приблизительное значение градиента путем вычисления разницы между значениями пикселей, которую также можно назвать приблизительной производной. Эта производная может быть выражена в исчислении.
В исчислении основное определение дифференциала первого порядка одномерной функции таково:
Изображение представляет собой двумерную функцию f(x, y), а ее дифференциал, разумеется, является частным дифференциалом. Итак, есть:
Поскольку изображение представляет собой дискретную двумерную функцию, ϵ не может быть бесконечно малым Наше изображение дискретно в пикселях, а наименьшее ϵ равно 1 пикселю. Следовательно, приведенное выше дифференцирование изображения принимает следующую форму (ϵ=1):
Это градиенты изображения в направлениях x и y в точке (x, y) соответственно.Как видно из приведенного выше выражения, градиент изображения эквивалентен разнице между 2 соседними пикселями.
Итак, как этот градиент (или скорость изменения значения серого) повышает резкость изображения?
Давайте сначала рассмотрим направление x, выберем определенный пиксель, предполагая, что его значение пикселя равно 100, а соседние пиксели вдоль направления x равны 90, 90, 90 соответственно, тогда, согласно приведенному выше расчету, его градиент направления x равен 10, 0, 0 соответственно. Здесь только абсолютное значение скорости изменения берется для обозначения величины изменения.
Мы видим, что разница в 10 по яркости между 100 и 90 не очень заметна, а вместе с большой группой непрерывных значений серого 90 приходится размывать контуры. Заметим, что если значение серого соседних пикселей изменяется, то градиент имеет значение, а если значение серого соседних пикселей не меняется, то градиент равен 0. Если мы добавим значение градиента к соответствующему пикселю, то если значение серого не изменится, значение пикселя не изменится, а если есть значение градиента, значение серого станет больше.
Мы видим, что на новом изображении после добавления яркость пикселей исходного изображения 100 и 90 отличается всего на 10, а теперь это 110 и 90, яркость отличается на 20, а контрастность явно повышена, особенно контуры и края объектов на изображении.Фон значительно усиливает различие, поэтому градиенты используются для улучшения изображений.
Выше сказано только направление x, направление y такое же. Так можно ли комбинировать градиенты в направлениях x и y? Конечно, это возможно. Градиенты в направлениях x и y могут быть выражены вместе следующим образом:
Вот квадрат и квадратный корень, и объем вычислений относительно велик, поэтому абсолютное значение обычно используется для аппроксимации операции квадрата и квадратного корня, чтобы уменьшить объем вычислений:
Разобравшись с принципом, давайте разберемся, какие градиентные фильтры предоставляет OpenCV?
В OpenCV он дает нам три разных градиентных фильтра или фильтра верхних частот: Sobel, Scharr и Laplacian. Что такое Qualcomm? На самом деле, это противоположно размытию изображения. Размытие изображения пропускает низкие частоты и блокирует высокие, что устраняет шум и сглаживает резкие края. Фильтр высоких частот пропускает высокие частоты и блокирует низкие, делая края более выраженными и улучшая изображение.
фильтр Собеля
Фильтр Собеля — это дискретный дифференциальный оператор, сочетающий сглаживание по Гауссу и дифференциальный вывод. Этот оператор использует локальные различия для поиска ребер, и вычисляется аппроксимация градиента.
Конкретный принцип заключается в следующем:
Фильтр Собеля сворачивается с исходным изображением для расчета изменения значения пикселя в горизонтальном направлении. Например, когда размер фильтра Собеля равен 3*3, горизонтальная частная производная вычисляется следующим образом:
Если вам нужно вычислить частную производную (градиент) в горизонтальном направлении P5, формула выглядит следующим образом:
P5x=(P3-P1)+2*(P6-P4)+(P9-P7)
Если вам нужно вычислить частную производную (градиент) в вертикальном направлении P5, формула выглядит следующим образом:
P5y=(P7-P1)+2*(P8-P2)+(P9-P3)
В OpenCV он предоставляет нам функцию cv2.Sobel() для реализации фильтра Собеля, и ее функция определяется следующим образом:
def Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None):
источник: исходное изображение
ddepth: глубина выходного изображения, подробные значения следующие:
ввод глубины изображения | выходная глубина изображения |
---|---|
cv2.CV_8U | -1/cv2.CV_16S/cv2.CV_32F/cv2/CV_64F |
cv2.CV_16U/cv2.CV_16S | -1/cv2.CV_32F/cv2.CV_64F |
cv2.CV_32F | -1/cv2.CV_32F/cv2.CV_64F |
cv2.CV_64F | -1/cv2.CV_64F |
dx: представляет порядок производной в направлении X
dy: представляет производный порядок в направлении Y
ksize: Размер ядра Собеля, при значении -1 для работы будет использоваться фильтр Собеля.
масштаб: Коэффициент масштабирования, используемый для расчета значения производной, значение по умолчанию равно 1, когда нет масштабирования.
delta: значение на целевом изображении загрузки, значение необязательное, по умолчанию 0
borderType: стиль границы, который подробно описан в предыдущем сообщении в блоге, поэтому я не буду здесь вдаваться в подробности.
Следует отметить, что если для параметра ddepth установлено значение -1, чтобы результаты обработки соответствовали исходному изображению, вы можете получить неправильные результаты. На самом деле это приведет к возможным отрицательным значениям градиента. Если обработка представляет собой 8-битное изображение, что означает, что результатом указанной операции также является 8-битный тип изображения, то все отрицательные числа будут автоматически усечены до 0, а информация будет потеряна. Во избежание потери информации в расчетах используется более высокий тип данных cv2.CV_64F, а затем он сопоставляется с типом cv2.CV_8U, принимая абсолютное значение. Итак, мы часто используем фильтр Собеля с ddepth, установленным в cv2.CV_64F.
Синтаксис для вычисления градиента в направлении X:
cv2.Sobel(src,ddepth,1,0)
Синтаксис для вычисления градиента в направлении Y:
cv2.Sobel(src,ddepth,0,1)
Синтаксис для вычисления градиента направления XY:
cv2.Sobel(src,ddepth,1,1)
Синтаксис для вычисления градиента суммирования XY:
dx=cv2.Sobel(src,ddepth,1,0)
dy=cv2.Sobel(src,ddepth,0,1)
dst=cv2.addWeighted(src1,alpha,src2,beta,gamma)
Поскольку могут быть отрицательные числа, нам также нужно использовать другую функцию для получения абсолютного значения, это функция: cv2.convertScaleAbs(), ее полное определение выглядит следующим образом:
def convertScaleAbs(src, dst=None, alpha=None, beta=None):
альфа: корректирующий коэффициент, необязательное значение, по умолчанию 1
бета: отрегулируйте значение яркости, по умолчанию 0
Далее воспользуемся фильтром Собеля для получения информации о границах в горизонтальном направлении изображения Код выглядит следующим образом:
import cv2
img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED)
sobel_x=cv2.Sobel(img,cv2.CV_64F,1,0)
result=cv2.convertScaleAbs(sobel_x)
cv2.imshow("img", img)
cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()
После запуска эффект следующий:
Далее воспользуемся фильтром Собеля для получения информации о границах в вертикальном направлении изображения Код выглядит следующим образом:
import cv2
img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED)
sobel_y=cv2.Sobel(img,cv2.CV_64F,0,1)#更改这一行就行
result=cv2.convertScaleAbs(sobel_y)
cv2.imshow("img", img)
cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()
После запуска эффект следующий:
Далее, давайте вычислим градиент направления XY, код выглядит следующим образом:
import cv2
img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED)
sobel_xy=cv2.Sobel(img,cv2.CV_64F,1,1)#都设置为1
result=cv2.convertScaleAbs(sobel_xy)
cv2.imshow("img", img)
cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()
После запуска эффект следующий:
Наконец, давайте вычислим информацию о наложенных краях в горизонтальном и вертикальном направлениях.Код выглядит следующим образом:
import cv2
img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED)
sobel_x=cv2.Sobel(img,cv2.CV_64F,1,0)
sobel_y=cv2.Sobel(img,cv2.CV_64F,0,1)
abx_x=cv2.convertScaleAbs(sobel_x)
abx_y=cv2.convertScaleAbs(sobel_y)
result=cv2.addWeighted(sobel_x,0.5,sobel_y,0.5,0)
cv2.imshow("img", img)
cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()
После запуска эффект следующий: