第二篇:介绍具体函数用法
图片读取、保存
- namedWindow():使用该函数创建一个空图片的窗口时,需要手动释放窗口资源(不推荐这种用法)
// imread()
Mat pic = imread("图片路径", 读取方式_可缺省); // 默认读取原图
// imshow()
imshow("窗口名", Mat对象名);
// imwrite()
imread("图片存储路径", 写入方式_可缺省);
视频操作
- VideoCapure 、VideoWrite
- VideoCapure 是一个类,对视频相关的操作进行了封装,类似于CWnd 对 HWND 的封装
- 可以先定义类对象 》打开视频 》视频的各种属性和操作就保存在类对象的成员中 》通过成员函数访问视频属性。
- 其资源的释放由类自己管理,也可以手动管理:类对象.release();
- 要注意不同 opencv 版本中,成员函数的参数写法。
VideoCapture video;
video.open("视频路径"); // video.open(1); 表示从摄像头读取数据
// 判断视频是否加载成功
if (!video.isOpened())
{
cout << "打开视频失败" << endl;
}else
{
cout << "打开视频成功" << endl;
// 获取视频属性
cout << video.get(CAP_PROP_FRAME_COUNT) << endl;
// 读取视频:视频 》 图片
while(1)
{
Mat flame;
video >> flame;
// 如果图片读取结束,推出循环
if(flame.empty())
{
break;
}
// 添加对每一帧图像的处理代码:
...
...
// 以下为显示原视频的代码:
imshow("播放视频", frame); // 显示当前帧
uchar kdown = waitKey(1000 / video.get(CAP_PROP_FPS));// 控制两帧之间的时间间隔,从而实现快放和慢放,其中video.get(CAP_PROP_FPS)表示获得视频帧率,即原视频中每秒的图片张数。
// 如果在播放过程中,键盘按下 q ,则退出播放视频
if(kdown == 'q')
{
break;
}
}
}
图像颜色模型:BGR、HSV
- BGR 模型:色彩空间是一个立方体
BGR 模型数据类型转换
【0~255】 CV_8UC3
【0~1】CV_32FC3:小于0表示全黑,大于1表示全白
【0~1】CV_64FC3:小于0表示全黑,大于1表示全白
Mat a(3, 3, CV_8UC3);
a.convertTo(b, CV_32F, 1/255.0, 0); // convertTo 对Mat对象数据处理
b表示转换后的Mat对象
CV_32F:转换后的数据格式
1/255.0:缩放系数
0:平移系数
- HSV 模型:色彩空间是一个锥形:锥形横截面(圆)的旋转角度、径向长度、锥深度,依次表示色调、饱和度、亮度
- GRAY 灰度模型:只有一种颜色灰色
- 3种颜色空间模型互相转换
void cv::cvtColor(Mat src, Mat gray, 转换格式)
// 特别注意:
// COLOR_BGR2GRAY,默认选用这个!因为默认是 BGR 格式
// COLOR_RGB2GRAY
// 二者的区别
多通道分离、融合
split 、merge,通过通道分离、融合可以验证:opencv默认存储顺序是 B、G、R,即第一个通道存储的是蓝色的数据
void cv::split(Mat src, Mat * dst);
// src :多通道图像;
// dst:向量形式的单通道图像,可以是 Mat img[3]
void cv::merge(Mat * src, int 通道数, Mat dst);
void cv::merge(vevtor<Mat> src, Mat dst);
// src:向量形式的单通道图像, 每个分量的大小和数据类型必须相同
// dst:合并后的Mat
像素运算
// 按照每个像素一一比较,将比较结果存储在 dst 中
// 灵活运用 黑白掩码图像,就可以实现对图片内容的遮盖
void cv::min(Mat src1, Mat src2, Mat dst);
void cv::max(Mat src1, Mat src2, Mat dst);
// 最大值最小值寻址:掩码作用???
// 只能处理单通道图像
void cv::minMaxLoc( Mat src,
doube * pSaveMin,
doube * pSaveMax,
Point * pSaveMinLoc = Null,
Point * pSaveMaxLoc = Null,
Mat mask = 缺省
);
// 逻辑运算
void cv::bitwise_or(Mat src1, Mat src2, Mat dst, Mat mask = 缺省);
void cv::bitwise_xor(Mat src1, Mat src2, Mat dst, Mat mask = 缺省);
void cv::bitwise_not(Mat src, Mat dst, Mat mask = 缺省);
void cv::bitwise_and(Mat src1, Mat src2, Mat dst, Mat mask = 缺省);
图像二值化
- 简单来说就是对图像像素值按照某一标准划分为两个数值,非此即彼。
// 固定阈值
double cv::threshold();
// 自适应阈值
// 本质是将原图切割成多个子图,对每个子图进行二值化处理
double cv::adaptiveThreshold();
type 还可以位或 大津法 和 三角形法,如:
LUT 查找表
- 本质是一个映射表,是 二值化 向 多值化 的一个推广
void cv::LUT(Mat src, // 只能是 CV_8U
Mat lut,
Mat dst, // 类型与 lut 相同
);
// lut 查找表可以是单通道,也可以是多通道(与src相同)
// lut 的每个通道必须是 1*256 的一个矩阵,对应0-255个像素值 所对应的映射值
// 这样就可以定向过滤、调整某些灰度的像素,
// 例如,将凸显中高亮的部分(>250)全部调整为 250,而其他的不变,那么 lut 就是 [0 1 2 ...249 250 ... 250 250]
缩放、翻转、拼接
- 图像插值
根据已有像素估计位置像素:最邻近插值、线性插值、双线性插值 - 图像缩放
void cv::resize(Mat src,
Mat dst,
Size dsize, // 缩放后尺寸
double fx = 0, // 缩放后 x 轴比例
double fy = 0, // 缩放后 y 轴比例
int interpolation = INTER_LINEAR // 标记了插值方式,默认双线性插值
);
// 如果 fx fy 与 dsize 冲突,则以 dsize 为准
INTER_AREA 缩小的时候用?
INTER_NEAREST 最近邻
INTER_LINEAR 双线性
INTER_CUBIC 双三次
- 图像翻转
void cv::flip(Mat src,
Mat dst,
int flipflag // 翻转方式:>0 绕y轴翻;=0 绕x轴翻;<0 现后绕x、y轴翻;
);
- 图像拼接
void cv::hconcat(Mat src1, Mat src1, Mat dst);
void cv::vconcat(Mat src1, Mat src1, Mat dst);
仿射变换(三点变换)
- 仿射 = 平移 + 缩放 + 旋转 + 翻转 + 错切
- 也就是图片在二维空间上的变换
X = [x, y]’
仿射过程就是线性变换过程
T = A* X + B
仿射变换矩阵:
M = [A B]
void cv::warpAffine(Mat src,
Mat dst,
Mat M, // 仿射变换矩阵, 在二维平面上,只能是 2*3 大小
Size dsize, // 输出图像尺寸
int flags, // 图像尺寸变化的时候的插值方式
int borderMode, // 因旋转而多出的部分图像像素外推方法
const Scalar & borderValue, // 因旋转而多出的部分图像像素制定填充值(默认0)
);
// borderMode、borderValue 都有指定的宏来标记具体方法
- 旋转 是一种特殊的仿射变换,没有提供专门的旋转函数,提供了计算 仿射矩阵 M 的函数
// 计算旋转变换仿射矩阵
Mat cv::getRotation2D(Point2f center, // 旋转中心,浮点型
double angle, // 旋转角,单位 度,逆时针为正
double scale // 两个轴的旋转缩放比例,缺省为 1
);
- 获得仿射变换矩阵
Mat cv::getAffineTransform(const Point2f * src[], // 原图中的三个坐标
const Point2f * dst[]); // 目标图中的三个坐标
透视变换(四点变换)
即三维图片在空间上的变换
- 获得透视变换矩阵
Mat cv::getPerspectiveTransform(const Point2f * src[], // 原图中的 4 个坐标,浮点数
const Point2f * dst[] // 目标图中的 4 个坐标
int solveMethod = DECOMP_LU
);
- 透视变换函数
void cv::warpPerspective(Mat src,
Mat dst,
Mat M, // 投射变换矩阵, 只能是 3*3 大小
Size dsize, // 输出图像尺寸
int flags, // 图像尺寸变化的时候的插值方式
int borderMode, // 因旋转而多出的部分图像像素外推方法
const Scalar & borderValue, // 因旋转而多出的部分图像像素制定填充值(默认0)
);
// borderMode、borderValue 都有指定的宏来标记具体方法
在图像中绘制内容
- 直线、圆、椭圆、矩形、多边形、文字
- line()
- circle()
- putText()
图像截取
Range(int iRow, int iCol)
Rect_(int x_lefttop,
int y_lefttop,
int width,
int height)
// 深拷贝:
cv::copyTO()
Mat::copyTO()
Mat::clone
高斯图像金字塔_(略)
作用:???
void cv::pyrDown(Mat src,
Mat dst,
Size dsize, // 输出图像尺寸,可缺省
int borderType // 像素边界外推法的标志
);
拉普拉斯金字塔_(略)
void cv::pyrUp(Mat src,
Mat dst,
Size dsize, // 输出图像尺寸,可缺省
int borderType // 像素边界外推法的标志
);
创建滑动条,调整图片参数
// 1. 定义滑块变量
int value
// 2. 定义回调函数
void barCallBack(int value, void * p)
{
// To do...
}
// 3. 按照以下格式创建滚动条
int cv::createTrackbar(const String & trackName,// 滑动条名称
const String & WndName, // 窗口名称
int * value, // 滑动条的位置数值由此数定义
int countMax, // 滑动条最大数值
void onChange(int value, void *), // 回调函数名
void * data // 传递给回调函数的参数(缺省)
)
// 说明:函数 createTrackbar 内部已经包含了“消息循环”,不需要
// 额外定义循环
鼠标时间响应函数_(略)
void cv::setMouseCallback(const String & WndName,// 响应窗口名
onMouse(), // 鼠标消息响应函数名
void * data // 传递给回调函数的参数(缺省)
)
MouseCallback(具体用法及其参数略过,
使用的时候再详细了解
)
绘制统计直方图
- 本质是统计图片中各个像素的分布情况,
- 通过对这部分的图像进行处理,就可以实现对图像特定部分进行处理
- 数据匹配
- 图片匹配
- 函数:
void cv::calcHist(省略)
// 该函数只输出统计数据,并不提供绘图功能
// 通常就是用之前讲到的,recTangle 函数画图
直方图均衡化
- 先获得直方图(图像灰度分布)
- 只能处理灰度图(单通道,CV_8UC1)
- 如果图片中部分过暗,隐藏了部分信息,需要提高这部分亮度,而不增加已经很亮的部分的亮度;反之也是如此。
- 均衡化最大作用就是:局部调整图片中过暗、过亮的部分,使图片中的信息更好的显示出来,而这种调整方式就涉及到部分数学知识,也就是数据处理
- 在直方图上体现为:将瘦高且偏左或偏右的灰度分布曲线,用数学的方式调整为宽胖且居中的曲线
void cv::equalizeHist(省略)
直方图匹配
- 人为指定/按照指定图片 中像素的分布模式,来对需要处理的图像进行均衡化处理
- 整个过程没有现成的接口函数,需要手动编写函数
- 在直方图上体现为:让灰度分布曲线重心集中在某一个地方
- 使用累计概率
- 让一张图的灰度图分布规律模仿另一张图的分布规律
- 即,按照看起来舒服的图的样子调整
图像模板匹配
- 在目标图像中搜索与模板图像一致的部分
void cv::matchTemplate(省略)
// 仅针对 CV_8U 和 CV_32F
// 获得图像中最大最小位置、最大最小值
void cv::minMaxLoc(省略)
图像卷积
- 常用于 图像边缘检测、去除噪声、图像压缩等过程
- 卷积核对所有像素进行操作(前提是扩充一圈像素)
- 卷积核要进行180°旋转 和 归一化(加权平均)
- 之所以具备滤波的功能,是因为 卷积核 的操作实际上是对像素周围的所有点(卷积核一般是技术的正方形)进行加权平均
// 从函数名来看,函数功能是进行二维滤波
void cv::filter2D(省略)
图像噪声的产生
- 椒盐噪声:随机产生的脉冲噪声,噪声点非黑即白
- 高斯噪声:噪声的分布密度服从高斯分布噪声的亮度不同
- 椒盐噪声没有特定的函数来生成模拟,只能随机函数来模拟
double cvflann::rand_double(省略)
int cvflann::rand_int(省略)
Q :噪声有什么用??
- 高斯噪声提供了函数:
void cv::RNG::fill(省略)
线性滤波
- 滤波效果是使图片变得模糊,边界不清晰
均值滤波与卷积类似,对像素中每一个像素位置进行处理,滤波器是一个 全1的奇数方阵/方阵和
// 均值滤波的函数
// 适用于单通道所有数据类型
void cv::blur(略)
方框滤波与均值滤波等价,不同之处在于,它不强制归一化,包含了均值滤波
// 该函数通过设置参数 包含了 blur()
void cv::boxFilter(略)
高斯滤波 滤波器可以不是方的,但必须是奇数,元素中心对称,数值按照高斯分布,中心位置值最大,所有元素和为1; 即是一种加权平均,中心权重最大, 其他地方权重负荷高斯分布
void cv::GaussianBlur(略)
非线性滤波
- 中值滤波 取滤波器的中值,如果滤波器中的像素分布中出现了一个异常的较大值或者较小值,就可以很好的滤除最大值、最小值,也就是椒盐噪声
- 滤波器必须是奇数
void cv::medianBlur(略)
线性滤波的可分离性
就是将原来矩形的滤波器分解成两个向量的乘积的形式,用两次滤波来代替原来的一次滤波
void cv::sepFilter2D(略)
边缘检测
图像的像素灰度值的梯度最大的地方,定义为边缘
所谓的边缘检测就是求解最大的梯度,
而求解梯度的过程就要用到上述的滤波、卷积的计算过程
实际上就是矩阵运算
以下算子本质是检测的矩阵——滤波器矩阵不同
- Sobel() 边缘检测算子获得边缘信息过多,包括虚假边缘
void cv::Sobel(略)
- Scharr() 边缘检测算子 (基于Sobel算子,在较小梯度的边缘检测的时候更有优势) 更多细节
void cv::Scharr(略)
以上两个算子都是调用getDerivKernels(略) 函数实现的,是两种特殊的情况,他们都是依次检测X、Y方向的边缘后叠加获得整幅图的边缘,
特点是:X方向更容易检测出Y反向的边缘,Y方向更容易检测出X反向的边缘,这就造成倾斜的边界被重复检测,当两个结果叠加的时候,这种倾斜的边缘亮度过高。
- Laplacian算子在一个识别过程中,对整幅图进行提取边缘,不用检测两次,由于使用了两次求导,更容易收到噪声的影响。它可以是彩色图。Laplacian() 函数的计算结果可能有负数,需要计算绝对值,用函数 convertScaleAbs()
void cv::Laplacian(略)
- Canny算子 对 Sobel算法进行优化,滤除虚假边缘(弱边缘),保留真实(强边缘)
void cv::Canny(略)
连通域分析(连通域分割)
连通域的概念:4邻域, 8邻域
- 1 通常先二值化处理
- 一层一层像素的分类,最后找到不同的连通域
// 函数1 :
// 只能处理 单通道 CV_8U 数据类型
int cv::connectedComponents(略)
// 函数2: 功能扩展
// 1. 输出每个连通域最大外边框的坐标、高宽、面积
// 2. 输出质心坐标
int cv::connectedComponentsWithStats(略)
图像距离判断
欧氏距离、街区距离、棋盘距离
具体怎么应用???
图像腐蚀
- 用于去除图像中的微小物体
- 分离较近的两个物体
- 处理二值化图像
- 简单理解就是设计一个结构元素,如果在原图像中能完全覆盖该结构元素,就保留该像素点,
- 实现的效果就是把粗线条变成细线条
// 生成结构元素函数
Mat cv::getStructingElement(略)
// 图像腐蚀操作函数
void cv::erode(略)
图像膨胀
- 与腐蚀对应
- 腐蚀是删除像素
- 膨胀是填充像素(不增加图幅)
- 也是需要用到结构元素
// 生成结构元素函数
Mat cv::getStructingElement(略)
// 图像腐蚀操作函数
void cv::dilate(略)
图像形态学操作(运用膨胀和腐蚀产生其他更多操作)
开运算 = 腐蚀 + 膨胀
- 可以去除图像中的噪声,消除较小连通域,保留较大连通域
- 腐蚀去除噪点(小连通域),膨胀还原大小(保留大连通域)
闭运算 = 膨胀 + 腐蚀
- 可以去除图像中的小空洞,平滑物体轮廓,连接两个临近的连通域
形态学梯度 = 原图膨胀结果 - 原图腐蚀结果
- 得到轮廓梯度(获得轮廓)
- 使用相同结构元素操作
顶帽运算 = 原图 - 原图开运算(???)
- 分离比邻近点亮一些的斑块(提取原图中分散的,较小的区域)
- 使用相同结构元素操作
黑帽运算 = 原图闭运算 - 原图(???)
- 分离比邻近点暗一些的斑块(提取原图中分散的,较小的区域)
击中击不中变换
- 找到与结构元素完全相同的布局
// 以上的通用接口函数,包括基础的膨胀与腐蚀
void cv::morphologyEx(略)
图像细化
- 将图像中的宽线条细化未单像素的过程,即骨架化,删除部分像素
// 扩展的 opencv 库函数
void cv::ximgproc::thinning(略)
轮廓检测、信息提取
- 用4个元素的数组来表示各个轮廓的层级关系 :[右边轮廓索引, 左边轮廓索引, 下边轮廓索引, 上边轮廓索引
findContours()
drawContours()
contourArea()
arcLenth()
轮廓外接多边形(拟合轮廓)
- 将图像的轮廓拟合成凹凸多边形
Rect cv::boundingRect(略) // 矩形拟合:返回轮廓外接正交矩形四个顶点
RotateRect cv::minAreaRect() // 矩形拟合:返回旋转矩形顶点
void cv::approxPolyDP() // 多边形拟合
凸包检测
- 将图像的轮廓拟合成凸多边形
void cv::convexHull()
直线检测
- 霍夫变换:二维直角坐标系中(原空间),通过一个点的直线族,表示为: y0 = k*x0 + b, 映射到 k 和 b 的坐标系中(参数空间),就表示一条直线,这就形成了 点—>线 的映射关系,由于 y=kx+b 不能映射垂直的直线,所以改进为用角度和距离这种方式映射,但不影响对原理的理解。
- 如果将原空间图像中每个非0点都映射成参数空间的一条直线,如果将参数空间离散化,映射的直线就是一系列方格,并在直线所在的方格上标记一次;
- 原空间中一条线中的两个点所表示的两个直线族,在参数空间中表示两条相交的直线;那么在参数空间中,就有一个点被重复标记了一次,如果参数空间中某个点被标记了足够多的次数,那么说明参数空间中,通过该点的所有直线 所对应的 原空间中的点都在一条直线上。
void cv::HoughLines()
void cv::HoughLinesP()
点集拟合
- 将离散的数据点进行拟合成确定的形状,允许拟合后的形状不通过数据点
- 直线拟合、圆形拟合、三角形拟合
- 用于数据处理
// 直线拟合
void cv::fitLine()
// 三角形拟合
void cv::minEnclosingTriangle()
// 圆形拟合
void cv::minEnclosingCircle()
QR二维码识别(略)
积分图像
- 对积分点左上角的矩形区域 求和/平方和
- 操作目的:加速图像处理过程,减少计算量
void cv::integral()
图像分割
- 漫水填充法
int cv::floodFill()
- 分水岭法
void cv::watershed()
角点检测