OpenCV图像处理
本文最后更新于 2026年3月31日 下午
学习OpenCV处理图像
OpenCV与图形学的关系

OpenCV与FFmpeg的关系

配置环境
安装Python环境(我本地自带conda环境,这步省略)
安装VS
安装xmake
- 需要配置环境变量
下载opencv源码
- opencv
- opencv-contrib 属于是探索版,高级扩展功能在这个里面
编译方法
- 1️⃣放的是opencv的源码路径
- 2️⃣放的是build目录(这个目录是自己新建的空目录)
- 3️⃣点击Config(根据环境自动生成编译脚本,需要等待一段时间,最后生成一堆的检测结果,即红色方框区域)

- 如果遇到哪个包没有的,就去网上下载下来的之后安装,然后点击4️⃣
Add Entry并重新执行一下3️⃣Config就可以了
- 4️⃣增加
安装FFMPEG
- 选择第一个网址点进去(第一个第二个都可以下载到)

下载选中区域的链接之后要配置一下环境变量: ......./bin到path
添加额外目录 opencv-contrib

- 最后点击
Generate,等待一会 - 用VS打开这个文件


- 所有需要编译出的文件在这里面就都有了

VScode运行测试

课程学习
基本图像运算与处理
创建和显示窗口
- namedWindow()
- imshow
- destroyAliWindows
- resizeWindow
Mat 深拷贝与浅拷贝
浅拷贝
- Mat A
- A =imread(file, IMREAD_COLOR)
- Mat B(A);
深拷贝
- cv:Mat::clone()
- cv:Mat::copyTo()
- copy()
- 前面两个是c++使用最后一个是Python使用
通道分离与合并
- split(mat)
- merge((ch1, ch2, …))
绘制图像
- 画线
- 画矩形
- 画圆
- 画椭圆:ellipse(img.中心点,长宽的一半,角度,从哪个角度开始到哪个角度结束,…)

- 画多边形:polylines(img,点,是否闭环,颜色,…)
- 填充多边形:fillPoly(img,点集,颜色)
- 绘制字体:putText(img,字符串,启始点,字体,字号,…)
- 划线的时候坐标顺序是(x,y)
图像运算
两个图像相加
两个图像相减
- 参数顺序有要求,不像加法,加法是没有要求的
- subtract(A,B)
- 含义是A减B
图像乘与图像除
- multiply(A,B)
- divide(A, B)
图像溶合
- addWeighted(A,alpha,B,bate,gamma)
- alpha和beta是权重
- gamma静态权重
图像位运算
图像变换
图像的缩放
- resize(src, dst, dsize, fx, fy, interpolation)
- fx:x轴的缩放因子
- fy: y轴的缩放因子
- interpolation:插值算法
- INTERNEAREST,邻近插值,速度快,效果差
- INTER_LINEAR,双线性插值,原图中的4个点 (默认)
- INTER_CUBIC,三次插值,原图中的16个点
- INTER_AREA,效果最好
- 如果dsize没有设定,那么就会选择选择fx和fy的值
图像翻转
- flip(img, flipCode)flipCode == 0 , 上下
- flipcode > 0,左右
- flipCode < 0,上下+左右
图像旋转
- rotate(img, rotateCode)
- ROTATE_9O_CLOCKWISE
- ROTATE_180
- ROTATE_9O_COUNTERCLOCKWISE
图像的仿射变换
- 仿射变换是图像旋转、缩放、平移的总称
- warpAffine(src, M, dsize, flags, mode, value)
- M:变换矩阵
- dsize输出尺寸大小
- flag:与resize中的插值算法一致
- mode:边界外推法标志
- value:填充边界的值
平移矩阵
- 矩阵中的每个像素由(x,y)组成
- 因此,其变换矩阵是2x2的矩阵
- 平移向量为2x1的向量,所在平移矩阵为2x3矩阵
变换矩阵
getRotationMatrix2D(center, angle, scale)
center中心点
angle角度
scale缩放比例
getAffineTransform(src[], dst[])
通过三个点可以确定变换的位置
透视变换
透视变换API
- warpPerspective(img, M, dsize,…)
- M是变换矩阵
- dsize是目标图像大小
变换矩阵
- getPersectiveTransform(src, dst)
- 四个点(图形的四个角)
图像滤波
- 一幅图像通过滤波器得到另一幅图像;其中滤波器又称为卷积核,滤波的过程称为卷积;

- 卷积过程

卷积
卷积核的大小
- 卷积核一般为奇数,如3x3、5x5、7x7等;一方面是增加padding的原因;另一方面是保证锚点在中间,防止位置发生偏移的原因;
- 卷积核大小的影响:
- 在深度学习中,卷积核越大,看到的信息(感受野)越多,提取的特征越好,同时计算量也就越大
锚点
边界扩充
- 当卷积核大于1且不进行边界扩充,输出尺寸将相应缩小;(这就是上面所说的padding)
- 当卷积核以标准方式进行边界扩充,则输出数据的空间尺寸将与输入相等

计算公式
- N = (W - F + 2P)/S+1
- N输出图像大小
- W源图大小;F卷积核大小;P扩充尺寸
- S步长大小
步长
低通滤波与高通滤波
- 低通滤波可以去除噪音或平滑图像
- 高通滤波可以帮助查找图像的边缘
图像卷积
- filter2D(src, ddepth, kernel, anchor, delta,borderType)
- ddepth:一般设置成-1 ,这个参数位深的意思,设置成-1之后,原始的是多少位深,就是多少位深(
输出与出入是保持一致的位深) - kernel:不同的卷积效果是不同的,低通去噪平滑,高通查找边缘
- anchor:锚点;不设置锚点的时候会根据kernel核的尺寸去寻找对应锚点
- delta:每一次滤波或者卷积之后得到的元素,每一次卷积之后得到的元素加一个delta值,默认是0
- borderType:边界类型;可以加黑边,也可以有映射的类型比如说可以给图像进行180度的翻转,多出来的图像就是翻转后的一个边,一般采用默认值
- 一般最重要的是:源 位深 核
例子:
- 上面是一个5 x 5 的一个核,这个核的作用就是将一个矩形中的所有值,每一个值都乘以 1 ,然后进行相加,算出一个总值来
- 然后乘以一个 1/25,也就是做一个平均值 ,对一个5 x 5 的这样一个矩形做一个平均值
- 这样当过滤一遍之后,将这个图像卷积之后,这个图像就会变得非常平滑,因为它把这个峰值给消掉了
低通滤波
方盒滤波与均值滤波
方盒滤波卷积核

- 参数a的作用:
- normalize = true, a = 1/W x H 宽分之一 x 高
- normalize = false, a = 1 不进行均值化

- 方盒滤波API:boxFilter(src, ddepth, ksize, anchor, normalize, borderType) (ksize=kernel size 是3x3还是nxn)
- 平均滤波(均值滤波):blur(src, ksize, anchor, borderType) 一般normalize都是true,所以常用blur;后面anchor和borderType都有默认值,所以一般不设
高斯滤波

- 作用:做高斯的模糊处理或者 平滑处理;主要是解决
高斯噪点
原理
- 越靠近边上比重越低,越靠近中心比重越高,此处的25虽然值不是最高的,但是比重是最高的

高斯权重
高斯滤波API
- GaussianBlur(img, kernel, sigmaX, sigmaY, …)
- sigmaX, sigmaY:分别是X和Y的延展宽度,最大的范围到中心点有多大误差
- sigma的作用:

- 没有sigma时:
中值滤波
- 假设有一个数组
[1556789],取其中的中间值作为卷积后的结果值。(前面的数组是排序之后的结果) - 中值滤波的优点是对胡椒噪音效果明显
- 胡椒噪音图
中值滤波API
- medianBlur(img, ksize)
双边滤波
- 优点:
- 可以保留边缘,
- 同时可以对边缘内的区域进行平滑处理
- 双边滤波的作用是进行美颜
原理
双边滤波API
- bilateralFilter(img, d, sigmaColor, sigmaSpace,…)
- sigmaColor和sigmaSpace课后研究 f
高通滤波
常见的高通滤波
- Sobel(索贝尔)(高斯);会先使用高斯滤波处理一遍;卷积核大小设置成
-1就是沙尔; - Scharr(沙尔);卷积核固定是1 且不可改变 对于3x3 索贝尔效果没有沙尔好,因为沙尔可以检测出更细的边缘线
- 对于索贝尔或者沙尔来说,在计算边缘的时候只能求一个方向的,要么是横轴要么是纵轴,最终的检测结果把横轴和纵轴的结果加在一起,也就是在使用索贝尔或者沙尔之后还要做一层加法运算才能得出最终的结果
- Laplacian(拉普拉斯):不用单独求X或Y的边缘,可以一下把横轴或者纵轴的边缘一下检测出来,缺点是对噪音敏感,因为内部没有降噪的处理
Sobel算子
- 先向x方向求导
- 然后在y方向求导
- 最终结果:|G|=|Gx|+|Gyl
- Sobel API:
- Sobel(src, ddepth, dx, dy, ksize =3,
如果把ksize设置成-1就是沙尔算法;dx=1就是求y的方向,dy=1就是求x的方向 - scale =1, delta =0,borderType = BORDER_DEFAULT)
这行几个参数一般都是不设置的
- Sobel(src, ddepth, dx, dy, ksize =3,
Scharr算子
- 与Sobel类似,只不过使用的kernel值不同
- 只是 3x3的核
- 可以识别细小的线条
- 很少使用,因为可以用Sobel设置成-1来替换沙尔
- Scharr只能求x方向或y方向的边缘,(如果dx dy都设置成1的时候会直接报错,索贝尔是可以都设置成1的)
- API:
- Scharr(src, ddepth, dx, dy.
- scale =1, delta =0,borderType = BORDER_DEFAULT )
这一行几个参数不常设置,一般用默认值
拉普拉斯算子
- 可以同时求两个方向的边缘
- 对噪音敏感,一般需要先进行去噪再调用拉普拉斯
- API:
- Laplacian(img, ddepth
- ksize =1, scale =1,borderType = BORDER_DEFAULT)
不常用参数,使用默认值
- ksize =1, scale =1,borderType = BORDER_DEFAULT)
- Laplacian(img, ddepth
边缘检测Canny
- 使用5×5高斯滤波消除噪声
- 计算图像梯度的方向(0°/45°/90°/135°)
- 取局部极大值
- 國值计算
Canny國值计算

- API:
- Canny(img, minVal, maxVal, …)
- 小于这个阈值就不认为是个边缘,大于这个阈值就肯定是边缘
- 在两个值之间的需要根据计算判断
形态学
- 什么是形态学处理:
- 基于图像形态进行处理的一些基本方法
- 这些处理方法基本是对二进制图像进行处理;
- 一般黑白图像,即使拿到彩色的,会通过颜色转变,变成灰色的再进行二进制的转换,变成只有白色跟黑色两种颜色,最后再做形态的处理,这样更方便处理
- 卷积核决定着图像处理后的效果
- 形态学图像处理:
- 腐蚀与膨胀(理解成缩小和放大,下面的几种方法都是腐蚀和膨胀的组合或者说跟这两个有密切的关系)
- 开运算:先缩小再放大,最后一个动作是放大的
- 闭运算:最后一个动作是缩小的
- 顶帽
- 黑帽
图像二值化
- 什么是二值化:将图像的每个像素变成两种值,如0,255
- 全局二值化
- 局部二值化
全局二值化
- threshod API:
- threshold(img, thresh, maxVal, type)
- img:图像,最好是灰度图
- thresh:國值
- maxVal:超过國值,替换成maxVal
- threshodType:
- THRESH_BINARY 和 THRESH_BINARY INV
对于最大值来说,这五个里面只有前面两个可以设置最大值,否则的话都是255 - THRESH_TRUNC
- THRESH_TOZERO 和 THRESH_TOZERO_INV
- THRESH_BINARY 和 THRESH_BINARY INV
- 两个返回值:执行结果和输出图像
阈值类型
- 下面这个图,前面2个是二进制图像,常用的也是前面两个,后面三个不是二进制图像,也不常用

由于光照不均匀以及阴影的存在,只有一个國值会使得在阴影处的白色被二值化成黑色,这是全局二值化的一个弊端,所以此时要采用自适应阀值
自适应阀值
- adaptiveThreshold API:
- adaptiveThreshold(img, maxVal, adaptiveMethod
type, blockSize, C) - adaptiveMethod:计算國值的方法
- 计算國值的方法:
- ADAPTIVE_THRESH_MEAN_C:计算邻近区域的平均值
- ADAPTIVE_THRESH_GAUSSIAN_C:高斯窗口加权平均值
- 计算國值的方法:
- blockSize:邻近区域的大小
- C:常量,应从计算出的平均值或加权平均值中减去
- type:
- THRESH_BINARY
- THRESH_BINARY_INV
- adaptiveThreshold(img, maxVal, adaptiveMethod
腐蚀
- 原理:

- 卷积核

- 腐蚀运算

- 腐蚀效果

- 腐蚀API:
- erode(img,kernel,iterations=1)
卷积核的类型
- 获得卷积核
- getStructuringElement(type, size)
- Size 值为:(3,3)、(5, 5)..
- 卷积核的类型
type:- MORPH_RECT
- MORPH_ELLIPSE
- MORPH_CROSS
膨胀
- 膨胀运算

- 虚线处是原图,实线是膨胀之后的图
- 卷积的时候只要保证卷积核的中心锚点不为零,经过卷积之后它的周边无论是零还是非零都变成了非零值
- 膨胀的卷积核越大,膨胀速度越快
- 膨胀效果:
- 膨胀API:
- dilate(img,kernel,iterations=1)
- 注意:
- 膨胀只支持黑底白字,不支持白底黑字,否则就会白屏
- 卷积核是0的时候也能够进行正常的膨胀
开运算
- 开运算=腐蚀+膨胀
- 开运算效果:(消除外面的噪点)
- 开运算API:
- morphologyEx(img, MORPH_OPEN, kernel)
- 第二个宏指的是开运算
闭运算
- 先膨胀后腐蚀
- 闭运算效果:(消除里面的噪点)
- 膨胀是中心锚点不为零,则周围零或者非零的都会变成非零
- 闭运算API:
- morphologyEx(img, MORPH_CLOSE, kernel) 就是第二个参数变成CLOSE就可以
形态学梯度
- 梯度=原图-腐蚀 (为了得到边缘)
- 梯度效果图:(外形上看就是掏一个膜具出来,模具的间隙看卷积核的大小)
- 梯度API:
- morphologyEx(img, MORPH_GRADIENT, kernel) 还是第二参数的不同,类型改成GRADIENT就可以
- 如果kernel比较小,腐蚀的就会比较小,kernel很大腐蚀就会很大
- 腐蚀很大的时候 原图-腐蚀 的时候边缘就不会这么清楚
顶帽运算
- 顶帽=原图 - 开运算 (剩下的就是外部的噪点)
- 顶帽效果图
- 只保留留细节部分,大的也就是左边这一块是不需要的

- API:
- morphologyEx(img, MORPH_TOPHAT, kernel) 还是类型有区别,改成
TOPHAT
- morphologyEx(img, MORPH_TOPHAT, kernel) 还是类型有区别,改成
黑帽运算
- 黑帽= 闭运算 - 原图(保留内部的噪点)
- 效果图:
- 黑帽API:
- morphologyEx(img, MORPH_BLACKHAT, kernel) 还是第二个参数的区别,改成
BLACKHAT
- morphologyEx(img, MORPH_BLACKHAT, kernel) 还是第二个参数的区别,改成
图像轮廓
- 具有相同颜色或强度的连续点的曲线
- 可以不用灰度也可以查找轮廓
- 轮廓示例:
- 直线也是一条曲线,也是有轮廓的,也可以查找出来,前提是有相同颜色或者相同强度
- 图像轮廓的作用:
- 可以用于图形分析
- 物体的识别与检测
- 注意点:
- 为了检测的准确性,需要先对图像进行二值化或Canny操作
- 画轮廓时会修改输入的图像
- 轮廓查找的API:
- findContours(img.
mode,
ApproximationMode…) - 两个返回值,
- contours
查找到的所有轮廓的列表 - hierarchy
层级;查找的所有轮廓之间是否有层级关系或者前后关系是通过hierarchy存储的
- contours
- mode:
- RETR_EXTERNAL=O,表示只检测外轮廓
- RETR_LIST=1,检测的轮廓不建立等级关系
- 顺序是从里到外,从小到大

- 顺序是从里到外,从小到大
- RETR_CCOMP=2,每层最多两级
- RETR_TREE=3,按树形存储轮廓 (常用)
- 从大到小,从右到左

- 从大到小,从右到左
- RETR_EXTERNAL=O,表示只检测外轮廓
- ApproximationMode:
- CHAIN_APPROX_NONE,保存所有轮廓上的点
- CHAIN_APPROX_SIMPLE,只保存角点
- findContours(img.
如何绘制轮廓
API:
- drawContours(img,contours, contourldx, color,
thickness …) - contourIdx,-1表示绘制所有轮廓
- color,颜色(0,0,255)
- thickness,线宽,-1是全部填充,1是细的线宽,2就是粗一点的
轮廓的面积和周长
- 轮廓的面积
- API:contourArea(contour)
- 轮廓的周长
- API:arcLength(curve, closed)
- curve:轮廓
- closed:是否是闭合的轮廓
- API:arcLength(curve, closed)
多边形逼近与凸包
- 左边是逼近,右边是凸包

- 多边形逼近API:
- approxPolyDP(curve,epsilon,closed)
- curve:轮廓
- epsilon:精度
- closed:是否是闭合的轮廓
- 凸包API:
- convexHull (points, clockwise, …)
- points:轮廓
- clockwise:顺时针绘制
外接矩形

- 最小外接矩形
- 同样是框三个点,红框就是按照白色闪电的最小面积去框选的
- API:
- minAreaRect(points)
- points:轮廓
- 返回值:RotatedRect(Rotated是旋转的意思,得到的结果是包含角度的)
- x,y
- width, height
- angle
- 最大外接矩形
- 同样是框三个点,绿色就是按照白色闪电的最大面积去框选的
- API:
- boundingRect(array) (这个array其实就是points)
- array:轮廓
- 返回值:Rect (这个是不包含角度的)
图像的分割
- 将前景物体从背景中分离出来
- 图像分割的方法:
- 传统的图像分割方法
-分水岭法原理- GrabCut法
- MeanShift法
- 背景扣除
- 基于深度学习的图像分割方法
- 传统的图像分割方法
分水岭法原理
- 分水岭法原理

- 分水岭法的问题:图像存在过多的极小区域而产生许多小的集水盆

- 红色是传统的,绿色是opencv式的
- 分水岭法的处理步骤:
- 标记背景
- 标记前景
- 标记未知域
- 进行分割
- 实战:分割硬币
分水岭API:
- watershed(img, masker)
- masker,前景、背景设置不同的值用以区分它们
局部二值化
轮廓查找
OpenCV图像处理
http://yething.github.io/posts/652836722.html















