【opencv 学习】【常用的图像卷积核】

今天学习不同样式的核对图像的影响
基本可以分成高通滤波和低通滤波两种
#一些低通滤波器,就是取图像的低频成分,实际上就是把图像弄得模糊/平缓,消除噪音点,如之前学习的均值滤波和高斯滤波。
#一些高通滤波器,就是取图像的高频成分,实际上就是把图像进行锐化处理,使图像的边缘信息更加突出,如Sobel算子、Prewitt算子、锐化滤波器等;

第一部分:低通滤波器

import cv2
import numpy as np


# 展示图像,封装成函数
def cv_show_image(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)  # 等待时间,单位是毫秒,0代表任意键终止
    cv2.destroyAllWindows()



# 一些核操作
# 第一部分:均值滤波和高斯滤波
img = cv2.imread('images/saoge.jpg')  # 读取原始图像
img = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)  # 图像太大,展示小点的。
cv_show_image('img_src', img)

# 定义一个3x3的均值核,所有的权值都是一样的
kernel = np.array([[1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9]], np.float32)
dst = cv2.filter2D(img, -1, kernel=kernel)
cv_show_image('mean_kernel', dst)

# 定义一个3x3的高斯核,离中心越近权值越重,离中心点越远,权值越小,权值的采样可以是使用正态分布的的采样
kernel = np.array([[1/16, 2/16, 1/16],
                   [2/16, 4/16, 2/16],
                   [1/16, 2/16, 1/16]], np.float32)
dst = cv2.filter2D(img, -1, kernel=kernel)
cv_show_image('gauss_kernel', dst)

均值滤波结果
请添加图片描述
高斯滤波结果
请添加图片描述
第二部分:锐化滤波

# 第二部分:图像锐化,突出中间像素,而抑制周边像素, 可以分为4-邻接和8邻接
# 例如 4-邻接
#      [[0, -1,  0],
#      [-1,  5, -1],
#      [ 0, -1, 0]]
# 例如 8-邻接
#      [[-1, -1, -1],
#      [-1,  9, -1],
#      [-1, -1, -1]]

kernel = np.array([[0, -1, 0], 
                   [-1, 4, -1], 
                   [0, -1, 0]], np.float32)  # 定义一个3x3的锐化核
dst0 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst0)
kernel = np.array([[0, -1, 0], 
                   [-1, 5, -1], 
                   [0, -1, 0]], np.float32)  # 定义一个3x3的锐化核
dst1 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[0, -1, 0], 
                   [-1, 6, -1], 
                   [0, -1, 0]], np.float32)  # 定义一个3x3的锐化核
dst2 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst2)

res = np.vstack((dst0, dst1, dst2))  # 垂直排列展示
cv2.imshow('Ruihua_k0_4', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

kernel = np.array([[-1, -1, -1], 
                   [-1, 7, -1], 
                   [-1, -1, -1]], np.float32)  # 定义一个3x3的锐化核
dst0 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[-1, -1, -1], 
                   [-1, 8, -1], 
                   [-1, -1, -1]], np.float32)  # 定义一个3x3的锐化核
dst1 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[-1, -1, -1], 
                   [-1, 9, -1], 
                   [-1, -1, -1]], np.float32)  # 定义一个3x3的锐化核
dst2 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst2)

res = np.hstack((dst0, dst1, dst2))  # 水平排列展示
cv2.imshow('Ruihua_k1_8', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

多种4邻接核锐化效果
请添加图片描述

多种8邻接核锐化效果
请添加图片描述
第三部分:一阶微分核

# 第三部分:一阶微分算子
# 图像中物体的边缘往往就是变化较为剧烈的部分(高频部分),对于一个函数来说,变化越剧烈的地方,对应的导数的绝对值也就越大。
# 图像就是一种二元函数,f(x,y)表示(x,y)处像素的值,
# 因此导数除了大小,还有方向。那么求图像在某方向上的一阶导数(或称图像的梯度),也就可以反映出图像在该处的变化程度,变化程度越快,在该方向的垂直方向可能就存在物体的边缘。
# 一阶微分算子可以计算出某个方向上物体的边缘,但往往对噪声较为敏感,且边缘检测敏感度依赖于物体的大小。

# Prewitt算子
# Prewitt算子就是对图像进行差分来近似对图像的某个部分求一阶导数。由于导数还具有方向性,
# 因此同样大小的Prewitt算子还有8种不同的类型,目的在于求上、下、左、右、左上、左下、右上、右下8个方向上的梯度。
# 例如向右梯度方向的算子
# [[-1, 0, 1],
#  [-1, 0, 1],
#  [-1, 0, 1]]
# 例如向右上梯度方向的算子
# [[ 0, 1, 1],
#  [-1, 0, 1],
#  [-1, -1, 0]]
# 例如向上梯度方向的算子
# [[1, 1, 1],
#  [0, 0, 1],
#  [-1, -1, -1]]
# 例如左上梯度方向的算子
# [[1, 1, 0],
#  [1, 0, -1],
#  [0, -1, -1]]
# 以此类推
kernel = np.array([[-1, -1, -1],
                   [0, 0, 0],
                   [1, 1, 1]], np.float32)  # 定义一个3x3的向下梯度的卷积核
dst_down = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst0)
kernel = np.array([[-1, 0, 1],
                   [-1, 0, 1],
                   [-1, 0, 1]], np.float32)  # 定义一个3x3的向右梯度的卷积核
dst_right = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst0)
kernel = np.array([[1, 0, -1],
                   [1, 0, -1],
                   [1, 0, -1]], np.float32)  # 定义一个3x3的向左梯度的卷积核
dst_left = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[1, 1, 1],
                   [0, 0, 0],
                   [-1, -1, -1]], np.float32)  # 定义一个3x3的向上梯度的卷积核
dst_up = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst2)

res = np.hstack((dst_down, dst_right, dst_left, dst_up))  # 垂直排列展示
cv2.imshow('YiJie_Prewitt', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

# sobel 算子
# Sobel算子则是Prewitt算子的改进版,对中间的元素适当进行了加权,Sobel算子之于Prewitt算子类似于高斯滤波之于均值滤波。
# 同样Prewitt算子,Sobel算子一样考虑方向
# 例如向右梯度方向的算子
# [[-1, 0, 1],
#  [-2, 0, 2],
#  [-1, 0, 1]]
# 例如向右上梯度方向的算子
# [[ 0, 1, 2],
#  [-1, 0, 1],
#  [-2, -1, 0]]
# 例如向上梯度方向的算子
# [[1, 2, 1],
#  [0, 0, 1],
#  [-1, -2, -1]]
# 例如左上梯度方向的算子
# [[2, 1, 0],
#  [1, 0, -1],
#  [0, -1, -2]]
# 以此类推
kernel = np.array([[-1, -2, -1],
                   [0, 0, 0],
                   [1, 2, 1]], np.float32)  # 定义一个3x3的向下梯度的卷积核
dst_down = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst0)
kernel = np.array([[-1, 0, 1],
                   [-2, 0, 2],
                   [-1, 0, 1]], np.float32)  # 定义一个3x3的向右梯度的卷积核
dst_right = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst0)
kernel = np.array([[1, 0, -1],
                   [2, 0, -2],
                   [1, 0, -1]], np.float32)  # 定义一个3x3的向左梯度的卷积核
dst_left = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[1, 2, 1],
                   [0, 0, 0],
                   [-1, -2, -1]], np.float32)  # 定义一个3x3的向上梯度的卷积核
dst_up = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst2)

res = np.hstack((dst_down, dst_right, dst_left, dst_up))  # 垂直排列展示
cv2.imshow('YiJie_sobel', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

多种Prewitt算子效果
请添加图片描述

多种Sobel算子效果
请添加图片描述

第四部分:二阶微分核

# 第四部分:二阶算子
# Prewitt算子和Sobel算子都是近似对图像进行一阶导数的计算,只能提取出某个具体方向的边缘。
# 一个函数的二阶导数为0时,代表此处的一阶导数取得极值,对应地也就表明原函数在此处的变化最大。
# 因此往往还可以根据图像的二阶导数过零点的位置,来预测图像中变化最剧烈的地方,也许对应物体的边缘。
# 与一阶微分算子不同,这些二阶微分算子对边缘的计算具有旋转不变性,也就是可以检测出各个方向上的边缘。

# Laplace算子
# Laplace算子可以近似计算出图像的二阶导数,具有旋转不变性,也就是可以检测出各个方向的边缘。
# Laplace算子分为两种,分别考虑4-邻接(D4)和8-邻接(D8)两种邻域的二阶微分。
# 例如一个3x3的4-邻接为
# 例如 4-邻接
#      [[0, -1,  0],
#      [-1,  4, -1],
#      [ 0, -1, 0]]
# 例如 8-邻接
#      [[-1, -1, -1],
#      [ -1,  8, -1],
#      [ -1, -1, -1]]
#
kernel = np.array([[0, -1, 0],
                   [-1, 4, -1],
                   [0, -1, 0]], np.float32)  # 定义一个3x3的向左梯度的卷积核
dst1 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[-1, -1, -1],
                   [-1, 8, -1],
                   [-1, -1, -1]], np.float32)  # 定义一个3x3的向上梯度的卷积核
dst2 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst2)

res = np.hstack((dst1, dst2))  # 垂直排列展示
cv2.imshow('ErJie_Laplace', res)
cv2.waitKey(0)
cv2.destroyAllWindows()


# LoG算子
# Laplace算子对噪声依然很敏感。因此常常先使用高斯滤波器对图像进行平滑操作,再使用Laplace算子计算二阶微分。
# 二者结合称为LoG算子(Laplacian of Gaussian),该算子可以更加稳定地计算图像的二阶微分。
# 例如一个常用的5x5的核为
#      [[0, 0,  1,   0, 0],
#       [0, 1,  2,   1, 0],
#       [1, 2,  -16, 2, 1],
#       [0, 1,  2,   1, 0],
#       [0, 0,  1,   0, 0]]
kernel = np.array([[0, 0,  1, 0, 0],
                   [0, 1,  2,   1, 0],
                   [1, 2,  -17, 2, 1],
                   [0, 1,  2,   1, 0],
                   [0, 0,  1,   0, 0]], np.float32)  # 定义一个3x3的向左梯度的卷积核
dst0 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[0, 0,  1, 0, 0],
                   [0, 1,  2,   1, 0],
                   [1, 2,  -16, 2, 1],
                   [0, 1,  2,   1, 0],
                   [0, 0,  1,   0, 0]], np.float32)  # 定义一个3x3的向左梯度的卷积核
dst1 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)
kernel = np.array([[0, 0,  1, 0, 0],
                   [0, 1,  2,   1, 0],
                   [1, 2,  -15, 2, 1],
                   [0, 1,  2,   1, 0],
                   [0, 0,  1,   0, 0]], np.float32)  # 定义一个3x3的向左梯度的卷积核
dst2 = cv2.filter2D(img, -1, kernel=kernel)
# cv_show_image('RuiHua', dst1)

res = np.hstack((dst0, dst1, dst2))  # 垂直排列展示
cv2.imshow('ErJie_LoG', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

Laplace算子效果
请添加图片描述

LoG算子
请添加图片描述

猜你喜欢

转载自blog.csdn.net/qq_29367075/article/details/122906284