参考:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/tutorials.html
一、图像处理
1、图像平滑处理
平滑 也称 模糊, 是一项简单且使用频率很高的图像处理方法。
>> 归一化块滤波器 (Normalized Box Filter)
最简单的滤波器, 输出像素值是核窗口内像素值的 均值。
>> 高斯滤波器 (Gaussian Filter)
最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。
>> 中值滤波器 (Median Filter)
中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。
>> 双边滤波 (Bilateral Filter)
- 目前我们了解的滤波器都是为了 平滑 图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。
- 类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。
2、形态学处理
>> 腐蚀与膨胀(Eroding and Dilating)
简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将 结构元素 作用于输入图像来产生输出图像。
用途:
- 消除噪声
- 分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
- 寻找图像中的明显的极大值区域或极小值区域。
膨胀
-
此操作将图像 与任意形状的内核 (),通常为正方形或圆形,进行卷积。
-
内核 有一个可定义的 锚点, 通常定义为内核中心点。
-
进行膨胀操作时,将内核 划过图像,将内核 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。
腐蚀
-
腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。
-
进行腐蚀操作时,将内核 划过图像,将内核 覆盖区域的最小相素值提取,并代替锚点位置的相素。
-
以与膨胀相同的图像作为样本,我们使用腐蚀操作。这一操作会使图像钟的亮区(背景)变细,而黑色区域则变大了。
>> 开运算 (Opening)
-
开运算是通过先对图像腐蚀再膨胀实现的。
-
能够排除小团块物体(假设物体较背景明亮)。
>> 闭运算(Closing)
-
闭运算是通过先对图像膨胀再腐蚀实现的。
-
能够排除小型黑洞(黑色区域)。
>> 形态梯度(Morphological Gradient)
-
膨胀图与腐蚀图之差
-
能够保留物体的边缘轮廓
>> 顶帽(Top Hat)
原图像与开运算结果图之差
>> 黑帽(Black Hat)
闭运算结果图与原图像之差
3、图像金字塔
>> 高斯金字塔
-
想想金字塔为一层一层的图像,层级越高,图像越小。
-
每一层都按从下到上的次序编号, 层级 (表示为 尺寸小于层级 ())。
-
为了获取层级为 的金字塔图像,我们采用如下方法:
-
将 与高斯内核卷积:
-
将所有偶数行和列去除。
-
-
显而易见,结果图像只有原图的四分之一。通过对输入图像 (原始图像) 不停迭代以上步骤就会得到整个金字塔。
-
以上过程描述了对图像的向下采样,如果将图像变大呢?:
- 首先,将图像在每个方向扩大为原来的两倍,新增的行和列以0填充()
- 使用先前同样的内核(乘以4)与放大后的图像卷积,获得 “新增像素” 的近似值。
4、基本的阈值操作
-
为了从一副图像中提取出我们需要的部分,应该用图像中的每一个像素点的灰度值与选取的阈值进行比较,并作出相应的判断。(注意:阈值的选取依赖于具体的问题。即:物体在不同的图像中有可能会有不同的灰度值。
-
一旦找到了需要分割的物体的像素点,我们可以对这些像素点设定一些特定的值来表示。(例如:可以将该物体的像素点的灰度值设定为:‘0’(黑色),其他的像素点的灰度值为:‘255’(白色);当然像素点的灰度值可以任意,但最好设定的两种颜色对比度较强,方便观察结果)。
>> 二进制阈值化
-
该阈值化类型如下式所示:
>> 反二进制阈值化
-
该阈值类型如下式所示:
>> 截断阈值化
-
该阈值化类型如下式所示:
>> 阈值化为0
-
该阈值类型如下式所示:
>> 反阈值化为0
-
该阈值类型如下式所示:
5、边缘检测
>> Sobel算子
假设被作用图像为 :
-
在两个方向求导:
-
水平变化: 将 与一个奇数大小的内核 进行卷积。比如,当内核大小为3时, 的计算结果为:
-
垂直变化: 将:math:I 与一个奇数大小的内核 进行卷积。比如,当内核大小为3时, 的计算结果为:
-
-
在图像的每一点,结合以上两个结果求出近似 梯度:
有时也用下面更简单公式代替:
Note
当内核大小为 时, 以上Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值)。 为解决这一问题,OpenCV提供了 Scharr 函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确,其内核为:
>> Laplacian 算子
- 二阶导数可以用来 检测边缘 。 因为图像是 “2维”, 我们需要在两个方向求导。使用Laplacian算子将会使求导过程变得简单。
- Laplacian 算子 的定义:
- OpenCV函数 Laplacian 实现了Laplacian算子。 实际上,由于 Laplacian使用了图像梯度,它内部调用了 Sobel 算子。
>> Canny 边缘检测
- Canny 边缘检测算法 是 John F. Canny 于 1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的 最优算法, 最优边缘检测的三个主要评价标准是:
- 低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。
- 高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
- 最小响应: 图像中的边缘只能标识一次。
Canny 使用了滞后阈值,滞后阈值需要两个阈值(高阈值和低阈值):
- 如果某一像素位置的幅值超过 高 阈值, 该像素被保留为边缘像素。
- 如果某一像素位置的幅值小于 低 阈值, 该像素被排除。
- 如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于 高 阈值的像素时被保留。
Canny 推荐的 高:低 阈值比在 2:1 到3:1之间。
6、霍夫线变换
- 霍夫线变换是一种用来寻找直线的方法.
- 是用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像.
OpenCV实现了以下两种霍夫线变换:
- 标准霍夫线变换
- 原理在上面的部分已经说明了. 它能给我们提供一组参数对 的集合来表示检测到的直线
- 在OpenCV 中通过函数 HoughLines 来实现
- 统计概率霍夫线变换
- 这是执行起来效率更高的霍夫线变换. 它输出检测到的直线的端点
- 在OpenCV 中它通过函数 HoughLinesP 来实现
7、霍夫圆变换
使用OpenCV函数 HoughCircles 在图像中检测圆.
8、Remapping 重映射
重映射是什么意思?
-
把一个图像中一个位置的像素放置到另一个图片指定位置的过程.
-
为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.
-
我们通过重映射来表达每个像素的位置 :
这里 是目标图像, 是源图像, 是作用于 的映射方法函数.
-
让我们来思考一个快速的例子. 想象一下我们有一个图像 , 我们想满足下面的条件作重映射:
会发生什么? 图像会按照 轴方向发生翻转. 例如, 源图像如下:
看到红色圈关于 x 的位置改变( 轴水平翻转):
-
通过 OpenCV 的函数 remap 提供一个简单的重映射实现.
9、仿射变换
- 使用OpenCV函数 warpAffine 来实现一些简单的重映射.
- 使用OpenCV函数 getRotationMatrix2D 来获得一个 旋转矩阵
10、直方图均衡化
用OpenCV函数 equalizeHist 对图像进行直方图均衡化
>> 图像的直方图是什么?
- 直方图是图像中像素强度分布的图形表达方式.
- 它统计了每一个强度值所具有的像素个数.
直方图均衡化的主要作用在于增强图像对比度。
11、直方图计算
12、直方图对比
使用OpenCV函数 compareHist 产生一个表达两个直方图的相似度的数值。
13、反向投影
>> 什么是反向投影?
- 反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式。
- 简单的讲, 所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。
- 使用OpenCV函数 calcBackProject 计算反向投影?
- 使用OpenCV函数 mixChannels 组合图像的不同通道?
>> 反向投影的工作原理?
-
我们使用肤色直方图为例来解释反向投影的工作原理:
-
假设你已经通过下图得到一个肤色直方图(Hue-Saturation), 旁边的直方图就是 模型直方图 ( 代表手掌的皮肤色调).你可以通过掩码操作来抓取手掌所在区域的直方图:
-
下图是另一张手掌图(测试图像) 以及对应的整张图像的直方图:
-
我们要做的就是使用 模型直方图 (代表手掌的皮肤色调) 来检测测试图像中的皮肤区域。以下是检测的步骤
-
对测试图像中的每个像素 ( ),获取色调数据并找到该色调( )在直方图中的bin的位置。
-
查询 模型直方图 中对应的bin - - 并读取该bin的数值。
-
将此数值储存在新的图像中(BackProjection)。 你也可以先归一化 模型直方图 ,这样测试图像的输出就可以在屏幕显示了。
-
通过对测试图像中的每个像素采用以上步骤, 我们得到了下面的 BackProjection 结果图:
-
使用统计学的语言, BackProjection 中储存的数值代表了测试图像中该像素属于皮肤区域的 概率 。比如以上图为例, 亮起的区域是皮肤区域的概率更大(事实确实如此),而更暗的区域则表示更低的概率(注意手掌内部和边缘的阴影影响了检测的精度)。
-
14、模板匹配
- 使用OpenCV函数 matchTemplate 在模板块和输入图像之间寻找匹配,获得匹配结果图像
- 使用OpenCV函数 minMaxLoc 在给定的矩阵中寻找最大和最小值(包括它们的位置).
15、在图像中寻找轮廓
- 使用OpenCV函数 findContours
- 使用OpenCV函数 drawContours
16、计算物体的凸包
使用OpenCV函数 convexHull
17、创建包围轮廓的矩形和圆形边界框
- 使用OpenCV函数 boundingRect 来计算包围轮廓的矩形框.
- 使用OpenCV函数 minEnclosingCircle 来计算完全包围已有轮廓最小圆.
18、为轮廓创建可倾斜的边界框和椭圆
- 使用OpenCV函数 minAreaRect
- 使用OpenCV函数 fitEllipse
19、轮廓矩
- 使用OpenCV函数 moments 计算图像所有的矩(最高到3阶)
- 使用OpenCV函数 contourArea 来计算轮廓面积
- 使用OpenCV函数 arcLength 来计算轮廓或曲线长度
20、多边形测试
使用OpenCV函数 pointPolygonTest