API

照例,我们搬一下官网的 API:

C++

void cv::filter2D(InputArray   src,OutputArray  dst,int          ddepth,InputArray   kernel,Point        anchor=Point(-1, -1),double       delta=0,int          borderType=BORDER_DEFAULT)

Python

 dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

函数详解

这个函数一般是用于图像的卷积,但 OpenCV 文档里说这个函数不完全等于图像卷积。这一点说实话我看到的时候也震惊到了,我一直是拿它当卷积来用的。但是仔细考虑后,我认为这一点完全是定义上的差异,日常用的图像卷积定义和这个函数的功能实际上是一致的。

HelloWorld

直接上手做往往能给人最直观的感受。因此,最开始这里我要放一个使用这个函数的最小化程序,可以称之为该函数的 hello world 程序。这个程序跑通了,就可以很方便地尝试其他参数的作用了。

# HelloWrold Program of cv.filter2D
# by Aling on 2021/1/18
import numpy as np
import cv2 as cvdef main():img = cv.imread("你想读的图片")# 定义卷积核kernel = np.ones((10, 10)) / 100# 执行滤波avg_filtered = cv.filter2D(img, -1, kernel)# 显示图片cv.imshow("Average filtered", avg_filtered)cv.waitKey(0)cv.destroyAllWindows()if __name__ == "__main__":main()

这个程序读取一张图片,并将其通过10 x 10 的卷积核作均值滤波并显示结果。

参数详解

同样的,这里把各个参数打一张表:

参数 类型 是否必须指定(默认值) 具体含义
src numpy.ndarray 原图像
ddepth int 目标图像深度(指数据类型)
kernel numpy.ndarray 卷积核
anchor tuple 否(卷积核中心) 卷积锚点
delta 是数据类就行 否(0) 偏移量,卷积结果要加上这个数字
borderType int(实际上是 enum 类) 否(cv.BORDER_DEFALUT) 边缘类型

src

这个参数没什么好说的,就是原图像。它可以是任何色彩模式,这就意味着如果你把原本送到这个函数里的图片从黑白变成了彩色(单通道变成了 3 通道),你并不需要更改其他参数。本身,对多通道的图像,卷积就是以通道为单位进行的。

ddepth

这个参数有点费解了。大部分情况下不需要管它是干嘛的,直接把它设成 -1 就没有任何问题。

参数名 ddepth ,英文是 desired depth,即期望深度。什么意思呢?我们来看它的可能取值表(来自这里):

输入深度(src.depth()) 期望深度(ddepth
CV_8U -1/CV_16S/CV_32F/CV_64F
CV_16U/CV_16S -1/CV_32F/CV_64F
CV_32F -1/CV_32F/CV_64F
CV_64F -1/CV_64F

这个表里的一大串 CV 打头的符号到底是什么意思呢?实际上这些符号的末尾字母对应了数据类型:

U == Unsigned int  # 无符号整型
S == Signed int    # 有符号整型
F == Float         # 浮点型

中间的数字很显然代表了数据类型所占用的空间(bit)。所以,所谓深度,其实指的是数据类型

那就好说了,你会发现这里其实是规定了输出数据的类型,包括每个通道的每个像素占用多少空间。输出数据的类型必须根据上面的表格中输入对应的类型指定。这里 -1 表示输出类型和输入相同

不过,值得注意的是,似乎有些数据类型无法通过 cv2.imshow 正常显示,可以用 matplotlib.pyplot.imshow 来代替。

但是,还是注意,没有关于数据类型的特别要求时,这个功能是不需要的,取 -1 即可。

kernel & anchor

这两个参数都是卷积相关的,因此放在一节里面讲述。接下来的内容假设你已经了解了图像卷积

这里,kernel 很显然表示的是卷积核,这是一个 numpy.ndarray 类型的矩阵。这个矩阵的生成可以用 numpy 自带的函数,但是对于复杂一些的卷积核,OpenCV 内部的一些函数显然更合适。如 getStructuringElementgetGaussianKernel,前者用于获取特定形状的核,后者则是高斯核生生成器(不过要注意生成的是一个向量)。

# 方法一示例
kernel = cv.getStructuringElement(cv.MORPH_RECT, (11, 11))# 方法二示例
vector = cv.getGaussianKernel(11, -1)
kernel = vector @ vector.T

anchor 则表示锚点。什么叫锚点呢?看下面这张图:

可以说,锚点 anchor 决定了卷积核相对于生成目标点的位置。虽然锚点是相对于卷积核来定义的,但是卷积的过程更像是通过锚点去寻找卷积核。遍历图像中的每一个像素,以每一个像素为锚点,按照相对位置生成卷积范围,和卷积核对应元素相乘再求和得到目标图像中对应像素的值。可以用公式表示成:
dst(x,y)=∑0≤x′<kernel.cols0≤y′<kernel.rowskernel(x′,y′)×src(x+x′−anchor.x,y+y′−anchor.y)\text{dst}(x, y)=\sum_{\begin{matrix}0\leq x^\prime < \text{kernel.cols} \\ 0 \leq y^\prime<\text{kernel.rows}\end{matrix}} \text{kernel}(x^\prime, y^\prime) \times \text{src}(x+x^\prime-\text{anchor.x}, y+y^\prime-\text{anchor.y}) dst(x,y)=0≤x′<kernel.cols0≤y′<kernel.rows​∑​kernel(x′,y′)×src(x+x′−anchor.x,y+y′−anchor.y)
这实际上就是一般的图像卷积计算方法。OpenCV 文档里面叙述的卷积定义则是需要将卷积核围绕锚点对称变换,再用上面的公式计算。这种方法更接近卷积原始的定义,但是对图像的卷积一般的应用而言(滤波、深度学习)这两种定义实际上没有什么区别。、

锚点用一个元组指定,是相对于卷积核左上角的坐标,从 0 开始

# 替换掉 HelloWorld 程序的对应行。
avg_filtered = cv.filter2D(img, -1, kernel, (1, 2))

delta

这个参数的存在其实有些费解,它的效果很简单,就是把卷积的结果加上一个固定的数字。直观上将,它将整个图像变亮或者变暗了。从应用上来说,它实际上将卷积过程扩展成了一般的线性运算(∗*∗ 表示卷积):
dst=kernel∗src+delta\text{dst} = \text{kernel} * \text{src} +\text{delta} dst=kernel∗src+delta
这个线性运算可以将结果限定在某一符合要求的范围内(比如大于 0),而且不会阻断梯度的传递。

borderType

这个参数更改的是 border 的生成方式。这个 border,也就是边缘,是在靠近边缘的部分卷积时用到的,参考上面那张图。无论 anchor 是什么,总有些边缘上的点对应的卷积范围无法完全落在原图内,这就需要对原图进行扩展。扩展的方法就是我们这里参数的含义。

这个参数取值是 OpenCV 里的 cv::BorderTypes enum 类定义的值,其可能取值及其对于边缘的作用结果如下图所示(图片来自 OpenCV Python 教程):

要注意几点:

  • cv.BORDER_WARP 在这个函数里面是不支持的;
  • cv.BORDER_CONSTANT 会将边缘取为 0(黑色),而且没法改,因为原函数并没有留出相关的接口。

扩展——滤波相关函数

图像滤波是一个很常用的功能,对此,OpenCV 也定义了很多函数。这里介绍的 cv.filter2D 是这些函数中可控性最高的,因为你可以用自定义的核进行卷积。但是一些常用的滤波,我们可以不必自己定义相应的核,直接用定义好的函数就可以了。

均值滤波

dst = cv.blur(img, (11, 11))# 等效于:
dst = cv.filter2D(img, -1, np.ones((11, 11))/11**2)

高斯滤波

dst = cv.GaussianBlur(img, (11, 11), -1)# 等效于
vector = cv.getGaussianKernel(11, -1)
kernel = vector @ vector.T
dst = cv.filter2D(img, -1, kernel)

中值滤波

dst = cv.medianBlur(img, 11)

注意中值滤波是取中位数作为目标值,是一个非线性滤波子,因此无法通过线性滤波的 cv.filter2D 来等效实现。

参考链接

  • 最新版 OpenCV 官方文档
  • OpenCV Python 教程
  • cv::filter2D 函数 API
  • cv::BorderTypes 参考页

OpenCV 图像卷积:cv.filter2D() 函数详解相关推荐

  1. OpenCV 图像缩放:cv.resize() 函数详解

    目录 系列前言 API 函数详解 参数列表 缩放方式其一 缩放方式其二 两种方式的优先级 关于插值方式 扩展 -- 相关函数 系列前言 这个系列是我第一个想要更下去的系列.每篇会全面介绍一个 Open ...

  2. 【opencv】25.图像卷积cv::filter2D()以及c++代码实例

    自己写图像锐化函数: #include <iostream> #include <opencv2/core.hpp> #include <opencv2/highgui. ...

  3. opencv cv.findContours 函数详解

    函数 cv.findContours contours, hierarchy = cv.findContours( image, mode, method[, contours[, hierarchy ...

  4. OpenCV-Python图像直方图计算calcHist函数详解、示例及图形呈现

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython ░ 一.引言 在前面几篇直方图相关的文章中介绍了直方图均衡.直方图匹配.局部直方图处理.基 ...

  5. [转载] OpenCV-Python图像位与运算bitwise_and函数详解

    参考链接: Python中的numpy.bitwise_and ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 一.概述 图像的与运算主要 ...

  6. OpenCV-Python图像位与运算bitwise_and函数详解

    ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 一.概述 图像的与运算主要用于获取某个图像中感兴趣的部分,是针对两个图像矩阵数组或一个数组 ...

  7. opencv中imgproc库中函数详解(1)

    BaseColumnFilter 单列核的基础滤波器. [cpp] view plaincopy class BaseColumnFilter { public: virtual ~BaseColum ...

  8. OpenCV-Python图像融合cv2.addWeighted权重加法函数详解

    ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 一.概述 在<OpenCV-Python图像的加法运算cv2.add函数详解> ...

  9. OpenCV-Python直方图计算calcHist函数详解

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython ░ 一.引言 在<<数字图像处理>第三章学习总结感悟2:直方图处理: h ...

最新文章

  1. (轉貼) 美電腦工程師改寫遊戲軟體向女友求婚成功 (News)
  2. Linux常见使用命令小结
  3. 20135202闫佳歆-第二章家庭作业-2.69
  4. 浙大1202 zoj1202
  5. Java面向对象和面向过程有什么区别?网友:傻傻分不清楚……
  6. MySQL 事务的面试题总结
  7. gan怎么输入一维数据_时空序列预测模型GAN+LSTM
  8. 不需要写代码,快速批量修改文件夹中图片的格式
  9. 微信小程序scroll-view中的坑(因为动态设置高度导致无法下拉)
  10. android 蓝牙耳机 找不到驱动程序,bluetooth外围设备,详细教您bluetooth外围设备找不到驱动程序怎么解决...
  11. 计算机技术在图形图像处理中的应用,计算机图形图像处理技术综述
  12. TOLUA的文件结构
  13. 操作系统-页面置换算法
  14. synchronized锁升级之轻量级锁
  15. VisualStudio2019 安装时下载不动或者显示下载失败
  16. 《redis 启动》 全网最全最新内容汇总(每月更新一次)
  17. Ubuntu磁盘管理
  18. c语言小游戏小人的移动,C乐趣之移动的小人
  19. SPSS随机对照研究总结
  20. GitLab版本升级跨大版本

热门文章

  1. 中国计量大学python期末试卷_中国大学慕课mooc用Python玩转数据期末考试搜题公众号答案...
  2. Docker系列教程一:入门知识点
  3. JS打造的三-级关链菜单通用版
  4. vue 对于el-table中表头使用下拉框
  5. 学习技术领导力(一)
  6. 创业冲突的五种解决方法是_五个处理厨师矛盾的方法,希望可以对后厨管理有所帮助...
  7. JVE非我全“芯”出击,多款越级新品即将发布
  8. Visual question answering: a state‑of‑the‑art review(二)
  9. 全民直播时代——直播平台源码基于WebRTC开发实时通信服务
  10. 如何做好苹果产品的清洁?清洁apple产品时需要注意什么?