前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenCV 滤波与卷积之 —— 自定义核卷积

OpenCV 滤波与卷积之 —— 自定义核卷积

作者头像
为为为什么
发布2022-08-09 15:07:37
2.3K0
发布2022-08-09 15:07:37
举报
文章被收录于专栏:又见苍岚

本文摘录OpenCV 中的卷积、滤波相关操作内容,重点介绍 Opencv 操作中自定义核进行卷积的操作。

用任意线性滤波器做卷积

到目前为止,我们所接触到的卷积都是在OpenCV中API内部实现了的。学习了一些卷积操作之后,就立即联系OpenCV中实现了相应功能的函数。在调用这些函数时,函数默认地选择了某一种核,我们做的只是向函数传递一些参数来调整这个核。在OpenCV中,实际是允许我们用一个真实存在的核进行卷积操作的。

卷积核分解

理论上说,我们只要用一个数组表示一个核,然后放进一个函数,就可以用来卷积了。实际情况中,一些不起眼的地方却会在很大程度上影响到性能,可分解的矩阵通常会产生这种影响。

一个可分核可以理解成两个一维核,在卷积时先调用x内核,然后再调用y内核。两个矩阵进行卷积所产生的消耗可以用两个矩阵的面积之积近似,如此一来,用n×n的核对面积为A的图像进行卷积所需的时间时An^2,但如果分解成n×11×n的两个核,那么代价就是An+An=2An,因此分解卷积核可以提高提高卷积计算的效率。只要n不小于3,这种计算方式能提高效率,并且。随着n的增大,这种收益愈发明显。

cv2.filter()

官方文档 使用自定义的卷积核对图像进行卷积

  • 函数使用
代码语言:javascript
复制
cv2.filter2D(
	src, 			# 源图像
	ddepth, 		# 输出图像深度
	kernel[, 		# 卷积核
	dst[, 			# 输出目标
	anchor[, 		# 锚点位置
	delta[, 		# 偏置项
	borderType]]]]	# 边缘 padding 外扩方式
	) -> dst

  • 示例代码
代码语言:javascript
复制
img = mt.cv_rgb_imread('img1.jpg', gray=False)
kernal = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
sob_res = cv2.Sobel(img, -1, 1, 0, ksize=3)
cus_res = cv2.filter2D(img, -1, kernal)
PIS(sob_res, cus_res)

cv2.sepFilter2D

官方文档 当卷积核可分时,运算效率会得到提示,那么可以使用 cv2.sepFilter2D 函数进行卷积

  • 函数使用
代码语言:javascript
复制
cv2.sepFilter2D(
	src, 				# 源图像
	ddepth, 			# 输出图像深度
	kernelX, 			# 1 × W 向量,但行卷积
	kernelY[, 			# H × 1 向量,单列卷积
	dst[, 
	anchor[, 
	delta[, 
	borderType]]]] ) -> dst

  • 示例代码
代码语言:javascript
复制
img = mt.cv_rgb_imread('img1.jpg', gray=False)
kernal_x = np.array([[-1, 0, 1]])
kernal_y = np.array([[1], [2], [1]])
sob_res = cv2.Sobel(img, -1, 1, 0, ksize=3)
cus_res = cv2.sepFilter2D(img, -1, kernal_x, kernal_y)
PIS(sob_res, cus_res)

生成卷积核

cv2.getDerivKernels()

官方文档 可以生成 Sobel 和 Scharr 的分解核

  • 函数使用
代码语言:javascript
复制
cv2.getDerivKernels(
	dx, 				# 关于 x 的导数阶。
	dy, 				# 关于 y 的导数阶。
	ksize[, 			# 核尺寸,可以是 1, 3, 5, 7 或 cv2.FILTER_SCHARR
	kx[, 				# 行滤波器系数的输出矩阵,ktype 类型。
	ky[, 				# 列滤波器系数的输出矩阵,ktype 类型。
	normalize[, 		# 是否规范化(缩小)过滤器系数(除以面积), 如果要操作浮点图像,配置此项为True。默认为 False
	ktype]]]]			# 可以为 cv2.CV_32F(默认) 或 cv2.CV_64F
	) -> kx, ky

  • 示例代码
代码语言:javascript
复制
kx, ky = cv2.getDerivKernels(1, 0, 3, ktype=cv2.CV_64F)

-->
kx
array([[-1.],
       [ 0.],
       [ 1.]])
ky
array([[1.],
       [2.],
       [1.]])

代码语言:javascript
复制
kx, ky = cv2.getDerivKernels(1, 0, 3, normalize=True, ktype=cv2.CV_64F)

-->
kx
array([[-0.5],
       [ 0. ],
       [ 0.5]])
ky
array([[0.25],
       [0.5 ],
       [0.25]])

代码语言:javascript
复制
kx, ky = cv2.getDerivKernels(1, 0, cv2.FILTER_SCHARR, normalize=False, ktype=cv2.CV_64F)

-->
kx
array([[-1.],
       [ 0.],
       [ 1.]])
ky
array([[ 3.],
       [10.],
       [ 3.]])

cv2.getGaussianKernel()

官方文档 用于生成 1D 高斯核

  • 数学表达
G_{i}=\alpha * e^{-(i-(\mathrm{ksize}-1) / 2)^{2} /\left(2 * \operatorname{sigma}^{2}\right)}

返回的核和为1

  • 函数使用
代码语言:javascript
复制
cv2.getGaussianKernel(
	ksize, 				# 核尺寸,需要是正奇数
	sigma[, 			# 标准差
	ktype]				# 系数数据类型,可以为 cv2.CV_32F(默认) 或 cv2.CV_64F
	) ->	retval

其中标准差参数 sigma 可以为 None,此时:

sigma =0.3 *((k s i z e-1) * 0.5-1)+0.8
  • 可以用两个 1D 高斯核生成 2D 高斯核
G_{2d}=G_{1d}G_{1d}^T
  • 示例代码
代码语言:javascript
复制
g1d = cv2.getGaussianKernel(9, 3)
g2d = np.matmul(g1d, g1d.T)
PIS(g2d)

示例源码

参考资料

  • 《学习 OpenCV3》 第十章
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年3月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用任意线性滤波器做卷积
    • 卷积核分解
      • cv2.filter()
        • cv2.sepFilter2D
        • 生成卷积核
          • cv2.getDerivKernels()
            • cv2.getGaussianKernel()
            • 示例源码
            • 参考资料
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档