!!!!!!多思考不要指望一步出结果,记住一句话:对于计算机输入的是垃圾,输出的也是垃圾
!!!!!!要想结果尽人意,就多动脑,多准备,多思考
1、核心模块
[High GUI]:
[Image Process]:
[2D Feature]:研究如何使用OpenCV中的特征点检测子,特征点描述子以及匹配框架
[Camera Calibration and 3D reconstruction]:
[Video Analysis]:
[Object Detection]:
[Machine Learning]:
[GPU加速]:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2、图像的加载保存和修改(主要是色彩空间的变换)
|加载图像:cv::imread():加载图像为mat文件,--参数1:为图像路径+文件名(jpg、png、gif各种格式)--|--参数2:加载图像类型--
--IMREAD_UNCHANGED:加载原图--|--IMREAD_GRAYSCALE:加载灰度图--|--IMREAD_COLOR:加载RGB格式图--
cv::namedWindows("Window title", WINDOW_AUTOSIZE):创建一个窗口OpenCV自动销毁
--WINDOW_AUTOSIZE自适应图像大小|--WINDOW_NORMAL和qt集成使用,允许改变
cv::imshow():根据窗口名称显示图像到具体窗口上去,参数1:窗口名称--|--参数2:待显示的矩阵--
|修改图像:cv::cvtColor()----#include <opencv2/opencv.hpp>才能调用cvtColor()函数
--参数1:原图像像素矩阵--|--参数2:转换后图像矩阵--|--参数3:转换的类型
|保存图像:cv::imwrite()----保存到指定路径,只有8或者16位的png jpg tiff的单通道文件格式及三通道的BGR图像可以通过该方式保存
----保存PNG格式的时候可以保存透明通道图片
----可指定压缩参数
----修改-[查看定义]-快捷键为(Alt+F1)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3、矩阵的掩膜操作
|获取图像像素指针:CV_Assert(myImage.depth() == CV_8U)
----Mat.ptr<uchar>(int i = 0):获取像素矩阵的指针,索引i表示第几行,从0开始计行数
----const uchar* current = myImage.ptr<uchar>(row)获得当前行指针
----获取当前像素点的像素值p(row, col) = current[col]
|像素范围处理函数:saturate_cast<uchar>--小于0强制等于0--|--0-255之间正常值--|--大于255强制为255
|图像掩膜操作:即卷积操作,掩膜又称Mask/Kernel
----[ex]:I(i, j) = 5*I(i1, j) - [I(i-1, j) + I(i+1, j) + I(i, j-1) + I(i, j+1)]这种掩膜可以提高图像对比度
|以上全部为写一个掩膜函数必要的API,接下来是使用OpenCV定义好的API进行掩膜操作
|----Mat kernel = (Mat_<char>(3, 3)<<0, -1, 0, -1, -5, -1, 0, -1, 0); //定义一个kernel(掩膜)
|----filter2D(src, dst, src.depth(), kernel); //过滤器进行掩膜操作,src为原图片矩阵,dst为变换后存放矩阵,src.depth()图片通道,kernel定义的卷积核
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4、Mat对象
----说明:Mat对象自动分配内存(无内存泄漏情况),分为头部和数据部分
[Mat构造函数及常用方法]
[构造函数/初始化种类]
|Mat::Mat()----无参数构造方法
|Mat::Mat(int rows, int cols, int type)----创建行数为 rows,列数为 col,类型为 type 的图像
|Mat::Mat(Size size, int type)----创建大小为 size,类型为 type 的图像
|Mat::Mat(int rows, int cols, int type, const Scalar& s)----创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s
|Mat::Mat(Size size, int type, const Scalar& s)----创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s
|Mat::Mat(const Mat& m)----将m赋值给新创建的对象,此处不会对图像数据进行复制,m和新对象共用图像数据,属于浅拷贝
|Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)----创建行数为rows,列数为col,类型为type的图像,此构造函数不创建图像数
据所需内存,而是直接使用data所指内存,图像的行步长由 step指定
|Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)----创建大小为size,类型为type的图像,此构造函数不创建图像数据所需内存,而是
直接使用data所指内存,图像的行步长由step指定
|Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)----创建的新图像为m的一部分,具体的范围由rowRange和colRange指定,此
构造函数也不进行图像数据的复制操作,新图像与m共用图像数据
|Mat::Mat(const Mat& m, const Rect& roi)----创建的新图像为m的一部分,具体的范围roi指定,此构造函数也不进行图像数据的复制操作,新图像
与m共用图像数据
[说明:]构造函数中,很多都涉及到类型type。type可以是CV_8UC1,CV_16SC1,…,CV_64FC4 等。
里面的 8U 表示 8 位无符号整数,16S 表示 16 位有符号整数,64F表示 64 位浮点数(即 double 类型);
C 后面的数表示通道数,例如 C1 表示一个通道的图像,C4 表示 4 个通道的图像,以此类推。
如果你需要更多的通道数,需要用宏 CV_8UC(n),例如:Mat M(3,2, CV_8UC(5));//创建行数为 3,列数为 2,通道数为 5 的图像
[常用方法和成员函数]
|void copyTo(Mat mat)----复制矩阵
|void convertTo(Mat dst, int type)----转换矩阵数据类型
|Mat clone()----
|int channels()----
|int depth()----深度
|bool empty()----是否为空
|uchar * ptr(i = 0)----获取图像指针,按行的指针
[说明:]A矩阵复制给B矩阵:----部分复制(只复制数据头和指针) Mat B(A)----
----全部复制 Mat B = A.clone() 或者 ----Mat B; A.copyTo(B)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5、读写像素
|Scalar intensity = img.at<uchar>(y, x);----读取GRAY图像的像素值(CV_8UC1)
或者Scalar intensity = img.at<uchar>(Point(y, x));
|Vec3f intensity = img.at<Vec3f>();----读取一个RGB像素点的像素值
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];
[说明:]Vec3b和Vec3F:
----Vec3b对应三通道的blue、green、red的uchar类型数据
----Vec3F对应三通道的float数据
----CV_8UC1转换成CV32F1数据:src.convertTo(dst, CV_32F)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6、图像混合
[理论:]线性混合理论:g(x) = f0(x)*(1 - a) + f1(x) ---- a属于0-1之间
|void cv::addWeighted(InputArray src1 , double alpha , InputArray src2 , double beta , double gamma , OutputArray dst , int dtype = -1)
----dst = saturate [src1 * alpha + src2 * beta + gamma] saturate范围限制函数(限制在0-255之间)
----InputArray src1--输入图像Mat类型矩阵src1
----double alpha--src1的alpha值
----InputArray src2--输入图像Mat类型矩阵src2
----double beta--src2的beta值
----double, gamma--gamma值
----OutputArray dst--输出混合图像矩阵dst(Mat)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
7、图像变换--调整亮度和对比度
[理论:]图像变换可以看作是以下操作:
--点操作:像素变换 [例如:]调整亮度和对比度
--区域操作:邻域变换
--g(i ,j) = a * f(i ,j) + b a > 0且b为增益变量
[重要的API:]
|Mat new_image = Mat::zeros( image.size(), image.type())
--创建一张与原图像同样大小和数据类型的空白图像
|saturate_cast<uchar>(value)
--限制像素值在0-255之间
|Mat.at<Vec3b>(y, x)[index] = value
--给每个像素点每个通道赋值
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
8、模糊操作
|smooth(平滑)/blur(模糊):其背后是卷积计算,一般卷积算子为线性计算,又称线性滤波
g(i , j) = sum_(k,l){f(i + k, j + l) * h(k , l)} sum_(k,l)表示求和,对下表k , l求和
|均值滤波:卷积算子都是一
[API]:blur(Mat src, Mat dst, Size(xradius, yradius), Point(-1, -1))
|高斯滤波:卷积算子是二维高斯分布
[API]:GaussianBlur(Mat src, Mat dst, Size(x, y), Sigmax, Sigmay)
其中Size(x, y)的(x, y)必须是正数和奇数
|中值滤波:使用统计排序滤波器(同理可以进行最大值滤波及最小值滤波),中值滤波很好抑制椒盐噪声
[API]:medianBlur(Mat src, Mat dest, ksize)
--中值滤波ksize必须大于1且必须为奇数
|高斯双边滤波:[磨皮美白,突出特征]
----均值滤波会丢失边缘图像信息,高斯滤波部分解决问题,所以使用高斯双边滤波
----高斯双边滤波是边缘保留的滤波方法,避免了边缘信息的丢失,保留了图像轮廓
----高斯双边滤波一半由均值滤波组成,一半由高斯滤波组成(像一个切开一半的山峰)
保留了均值滤波的值域核信息 以及 高斯滤波的空域核信息
[API]:bilateralFilter(src, dest, d , sigmaColor, sigma Space)
--d 计算的半径,在该半径内的像素纳入计算,为-1则根据sigma Space进行计算
--sigmaColor 决定多少差值之内的像素会被计算
--sigma Space 当d大于0时,申明无效,否则根据其进行计算d值
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9、膨胀与腐蚀
形态学操作:膨胀、腐蚀、开、闭(基于集合论的形态学的四个基本操作)
图像形态学要求使用的结构元素/掩膜(具有旋转不变和镜像不变性),像素对称
|腐蚀:将物体边界进行腐蚀使其缩小的操作
|膨胀:将背景点融入物体中的操作
[说明:]膨胀腐蚀基本上为基本操作,以下开、闭、黑帽、
|开操作:先腐蚀后膨胀,用于消除纤细的小物体,平滑大物体边界
--消除小白点
|闭操作:先膨胀后腐蚀,填补物体内部细小孔洞,连接近邻物体,平滑边界不改变面积
--消除小黑点
|形态学梯度:膨胀减去腐蚀(只是基本梯度,还包括内部梯度[ 原图 - 腐蚀 ]、方向梯度[ x方向 y方向等 ]等)
(gradient ) [dilate - erode]
--描述图像轮廓
|顶帽操作:原图像与开图像之间的差值图像
--顶帽把该消除的小白点留下来,大图反而除去
|黑帽操作:原图像与闭图像之间的插值图像
--
[API]:----Mat kernel = getStructuringElement(int shape, Size ksize, Point anchor)
--Size的定义直接影响到过滤的效果
--形状(MORPH_RECT/MORPH_CROSS/MORPH_ELLIPSE)
--大小:ksize 为奇数
--锚点:默认是中心像素,即Point(-1, -1)
----dilate(src, dst, kernel)
--膨胀,简单说就是让明亮色素增加,可以消除黑点底噪
----erode(src, dst, kernel)
--腐蚀,简单说就是让暗色素增加扩大,可以消除白点底噪
----TrackBar - createTrackbar(const String & trackbarname, const String winName, int* value, int count, Trackbarcallback func, void* userdata = 0)
--该函数可在显示图像的窗口中快速创建一个滑动控件,用于手动调节阈值,具有非常直观的效果
--trackbarname:滑动空间的名称
--winname:滑动空间用于依附的图像窗口的名称
--value:初始化阈值
--count:滑动控件的刻度范围
--TrackbarCallback是回调函数
--其定义如下:typedef void (CV_CDECL *TrackbarCallback)(int pos, void* userdata)
----morphologyEx(src ,dst , op, kernel) src是原图像 |dst 是目标图像
--进行各种进一步图像操作的API
--op:各种CV_MOP_OPEN / CV_MOP_CLOSE / CV_MOP_GRADINET / CV_MOP_TOPHAT / CV_MOP_BLACKHAT形态学操作类型
开操作 闭操作 形态学梯度
--kernel:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
10、图像的降采样和上采样
图像金字塔:对图像进行降采样,使其变为分辨率越来越低的图像的过程
同样是放大(Zoom in)和缩小(Zoom out),不同于几何变换这里是降采样和上采样的方式
|高斯金字塔:对图像进行降采样
--从底向上逐层降采样,每次采样后(M * N)的图像变成(M/2 * N/2)图像(其实就是删除偶行的行列像素)
--步骤一:对图像进行高斯滤波/模糊
--步骤二:降采样--删除偶数行列的像素,得到图像为原图像的1/4
|拉普拉斯金字塔:根据上层降采样图片,重建图片
|高斯分差(Difference of Gaussian DOG):使用不同高斯核进行高斯模糊,对所得图像进行相减,最后输出结果
--高斯不同是图像的内在特征,在灰度图像增强,角点检测中经常用到
--高斯分差会导致像素差值太小,使用归一化增加像素值
--normalize(src, dst, 255, 0, NORM_MINMAX);
|拉普拉斯分差:同上
[API]:上采样(cv::pyrUp) - zoom in 放大
----pyrUp(Mat src, Mat dst, Size(src.cols * 2, src.rows * 2)) 生成图像为原图像高、宽的2倍
降采样(cv:pyrDown) - zoom out 缩小
----pyrDown(Mat src, Mat dst, Size(src.cols / 2, src.rows / 2)) 生成图像为原图像高、宽的1/2
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11、基本阈值操作
----图像阈值(threshold):像素分割的标尺
----阈值类型:--阈值二值化(threshold binary):相当于把高于某个阈值的所有像素归为大的值(如255),低于某个阈值的像素归为小的值(如0)
--阈值反二值化(threshold binary Inverted):把高于阈值的所有像素归为小的值(如0),低于某个阈值的像素归为大的值(如255)
--阈值取零(threshold to zero):低于某个阈值的全部像素取零
--阈值反取零(threshold to zero inverted):高于阈值的全部像素取零
[API]:|THRESH_BINARY:阈值二值化
|THRESH_BINARY_INV:阈值反二值化
|THRESH_TRUNC:高于阈值的所有像素变为阈值,低于阈值的所有像素不变
|THRESH_TOZERO:阈值取零
|THRESH_TOZERO_INV:阈值反取零
|THRESH_MASK:
|THRESH_OTSU:阈值自动计算并设置,外部无法进行改变
|THRESH_TRIANGLE:也是自动计算阈值的方式,不过计算算法与OTSU不同
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12、图像边缘
----卷积边界问题:图像卷积的时候边界像素不能被卷积,对于3*3卷积核有1个像素没有被使用,对于5*5卷积核有两个像素没有被使用
----处理边缘模式:卷积之前增加边缘像素,填充的像素值为0或RGB黑色,卷积之后就可以自动除去边缘像素
--BORDER_DEFAULT:默认处理方式
--BORDER_CONSTANT:填充边缘用指定像素值
--BORDER_REPLICATE:使用已知的像素值填充边缘像素
--BORDER_WRAP:使用另一边的像素值来补偿填充
[API:] |copyMakeBorder(Mat src, Mar dst, int top, int bottom, int left, int right, int bordertype, Scalar value)
--Mat src----输入图像矩阵
--Mar dst----输出图像矩阵
--int top, int bottom, int left, int right----图像添加的值,一般都是一样的
--int bordertype----边缘类型
--Scalar value----
|RNG 类:用于生成随机数
----RNG rng(12345); --12345是随机参数,可用1234都可以
----int c = rng.uniform(int a, int b); --c等于a和b之间的int值,除此之外double、float都可以
|waitKey函数的功能:
----等待x ms,如果在此期间有按键按下,则立即结束并返回按键的ASCII码,否则返回-1;
----如果x=0,则无限等待下去,直到有按键按下;
----在imshow之后,如果没有waitKey语句则不会显示图像
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
13、Canny算法检测
----是各种图像处理的基本步骤的集合
[步骤]: --高斯模糊:GaussianBlur
--灰度转换:cvtColor
--计算梯度:Sobel/Scharr
--非最大信号抑制:在各个方向上比较某一点比前后两个点都大则保留,否则舍弃
--高低阈值输出图像:-设置高阈值A和低阈值B(一般设置高阈值为整体的70%,高阈值一般为低阈值的2或1.5倍)
-高于阈值A的置为255,低于低阈值的置为0
-在A、B之间的像素值每一点进行考察,如周围没有值为255的则视为孤立点舍去,如有则置为255
-最后连接每一个像素值
[API]:cv::Canny(InpuyArray src, OutputArray dst, double threshold1, double threshold2, int aptertureSize, bool L2gradient)
----如果不事先进行滤波等操作,canny也会帮我们做
----InpuyArray src:8-bit的输入图像
----OutputArray dst:输出边缘图像,一般为二值图像,背景为黑色
----double threshold1:低阈值,通常为高阈值的1/2 或 1/3
----double threshold2:高阈值
----int aptertureSize:Sebel算子的size,通常为3*3
----bool L2gradient:true表示L2归一化,否则为L1归一化
L2为Gx和Gy各自平方求和再开根号,L1为Gx和Gy各自求绝对值再求和
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
14、霍夫变换
----
----[霍夫变换之直线]:(Hough Line Transfrom)
----用来作直线检测,前提条件是边缘检测已经完成
----平面坐标到极坐标变换,霍夫空间本质上是一个极坐标空间,某一点从平面坐标转换成极坐标转换公式:r=xcosθ+ysinθ
固定(x, y),做出r随θ变化曲线
----对于相交于一点的不同直线,固定该点后并做r-θ变化曲线,来自不同直线的该点所做r-θ曲线一致
----同一条直线上不同点全部做r-θ变化曲线后过同一点,该点信号最强
[API]:|cv::HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0, double min_theta = 0, double max_theta = CV_PI)
----标准霍夫变换
----InputArray image--输入图像,必须是8-bit的灰度图
----OutputArray lines--输出极坐标表示直线
----double rho--生成极坐标时的像素扫描步长,设置为1
----double theta--生成极坐标时的角度步长,一般为CV_PI/180
----int threshold--阈值,只有获得足够交点的极坐标值才被视为直线
----double srn=0--是否应用多尺度霍夫变换,设置为0表示为经典霍夫变换
----double stn=0--是否应用多尺度霍夫变换,设置为0表示为经典霍夫变换
----double min_theta = 0--表示扫描角度为0-180,默认即可
----double max_theta = CV_PI--
[说明]:一般为有经验的开发者使用,自己翻转到平面空间
|cv::HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold,double minLineLength=0, double maxLineGap=0 )
----统计霍夫变换
----InputArray image--输入图像,必须是8-bit的灰度图
----OutputArray lines--输出极坐标表示直线
----double rho--生成极坐标时的像素扫描步长,设置为1
----double theta--生成极坐标时的角度步长,一般为CV_PI/180
----int threshold--阈值,只有获得足够交点的极坐标值才被视为直线
----double minLineLength=0--最小直线长度
----double maxLineGap=0--最大间隔
----[霍夫空间圆]:(Hough Circle)
----霍夫空间圆利用在圆心处信号最强,来对圆进行检测
----霍夫圆检测对噪声敏感,所以先进行中值滤波
----基于效率考虑,OpenCV实现霍夫圆检测分两步:
--1、检测边缘发现可能圆心
--2、基于第一步基础,从候选圆心中开始计算最佳半径
[API]:|cv::HoughCircles(InputArray image, OutputArray circles, Int method, Double dp, Double mindist, Double param1, Double param2, Int minradius, Int maxradius)
----InputArray image--输入图像,必须是8-bit的灰度图
----OutputArray circles--输出结果,发现圆的信息
----Int method--方法:HOUGH_GRADIENT
----Double dp--dp = 1
----Double mindist--可以分辨两个圆的最短信息,否则认为是同心圆
----Double param1--canny edge detection high threshold
----Double param2--中心点累加阈值 候选圆心
----Int minradius--最小半径
----Int maxradius--最大半径
[说明]:LINE_4/LINE_8都有锯齿,LINE_AA无锯齿
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
15、像素映射
----将图片中每一个像素按照一定的规则映射到另一个图片中去,可以做到图片左右翻转等
[API]:cv::Remap(InputArray src, OutputArray dst, InputArray map1, OutputArray map2, int interpolation, int borderMode, const Scalar borderValue)
----InputArray src--输入图像
----OutputArray dst--输出图像
----InputArray map1--x映射表
----OutputArray map2--y映射表
----int interpolation--选择插值方法,常见线性插值、可选择立方等
----int borderMode--BORDER_CONSTANT
----const Scalar borderValue--color
[说明]:通过map1和map2可以建立映射关系,从而实现图像的变换
map1 和 map2 是通过操纵像素值下标,而不是像素值本身
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
16、直方图均衡化
----直方图(histogram)均衡化:对灰度图像的像素值(0-255)做直方图统计,称图像直方图
均衡化操作就是,拉伸图像灰度值范围,从而提高图像对比度(一种提高图像对比度的方法)
[API]:cv::equalizeHist(InputArray src, OutputArray dst)
----InputArray src--输入图像
----OutputArray dst--输出图像
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
17、直方图计算和比较
----直方图计算:除了基于像素值,包括基于像素值角度,像素梯度等各种直方图计算
--dims:维度,对于灰度图像来说只有一个维度
--bins:维度中子区域大小划分
--range:值的范围,灰度值范围在(0 - 255)之间
----直方图比较:将两张图像的直方图H1和H2,归一化到相同的尺度空间,通过计算H1和H2之间的距离,进而得到两个直方图的相似距离,从而比较两个图像的相似程度
--OpenCV提供的四种比较方法:
--相关性比较(correlation):CV_COMP_CORREL 最常用,为1最相似
--卡方比较(chi-square):CV_COMP_CHISQR 次于1、4
--十字交叉性(intersection):CV_COMP_INTERSECT 不常用
--巴氏距离(bhatt distant):CV_COMP_BHATTACHARYYA 很准,为0最相似(1 - 巴氏距离)
--直方图比较步骤:
--首先把图像从RGB空间转换到HSV色彩空间
--计算图像的直方图,然后归一化到[0-1]之间,使用calcHist和normalize
--使用上述四中比较方法进行比较compareHist
[API]:|split(const & Mat src, Mat * mvbegin)
----把多通道图像变为多个单通道图像
----const & Mat src--输入图像
----Mat * mvbegin--输出多通道图像数据
|calcHist(const Mat *images, int images, const int * channels, InputArray mask, OutputArray hist, int dims, const int * histsize, const float * ranges, bool uniform, bool accumulate)
----直方图计算
----const Mat *images--输入图像指针
----int images--图像数目
----const int * channels--通道数
----InputArray mask--输入mask,可选 ,不用
----OutputArray hist--输出直方图数据
----int dims--维数
----const int * histsize--样本的分的组数
----const float * ranges--值域范围
----bool uniform--默认是真(true by default)
----bool accumulate--默认是假(false by default)
|compareHist(InputArray H1, InputArray H2, int method)
----InputArray H1--直方图数据
----InputArray H2--直方图数据
----int method--比较方法
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
18、直方图反向投影
----反映直方图模型在目标图像中的分布情况
----简单点说就是,直方图模型去目标图像中寻找是否有相似的对象,通常使用HSV色彩空间中的H、S两个通道的直方图模型
[步骤]:--加载图像--imread
--将图像从RGB色彩空间转换到HSV色彩空间--cvtColor
--计算直方图和归一化--calcHist--normalize
--Mat或者是MatND,其中Mat表示二维数组,MatND表示三维或多维数组
--计算反向投影图像--calcBackProject
[API]:|mixChannels(const Mat* src,int nsrc,Mat* dst ,int ndst,const int* fromTo,size_t npairs)
----主要就是把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)的某些通道中,其中的对应关系就由fromTo参数指定.
----const Mat*--输入矩阵,可以为一个也可以为多个,但是矩阵必须有相同的大小和深度
----int nsrc--输入矩阵的个数
----Mat* dst--输出矩阵,可以为一个也可以为多个,但是所有的矩阵必须事先分配空间(如用create),大小和深度须与输入矩阵等同
----int ndst--输出矩阵的个数
----const int* fromTo--设置输入矩阵的通道对应输出矩阵的通道
----size_t npairs--即参数fromTo中的有几组输入输出通道关系,其实就是参数fromTo的数组元素个数除以2
[通道说明如下]:
|calcBackProject (const Mat * images, int nimages, const int * channels, InputArray hist, OutputArray backProject, const float ** ranges, double scale = 1, bool uniform = true)
----使用直方图模型,把待检测模型中的每个像素点拿到直方图中,看像素点在哪个bin区域中,就在新建立的空白图像中对应位置赋予bin的值(用左右或中间值都行)
----const Mat * images--输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
----int nimages--输入图像的数量
----const int * channels--用于计算反向投影的通道列表,通道数必须与直方图维度相匹配
----InputArray hist--输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
----OutputArray backProject--目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
----const float ** ranges--直方图中每个维度bin的取值范围
----double scale = 1--可选输出反向投影的比例因子
----bool uniform = true--直方图是否均匀分布(uniform)的标识符,有默认值true
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
19、模板匹配
----模板匹配是最简单的最基本的模式识别,需要一个模板图像T和一个原图像S,按从左到右从上到下一次匹配图像,计算两者匹配度
----图像匹配方法:
--计算平方不同----CV_TM_SQDIFF --值越小越相关
--计算相关性----CV_TM_CCORR --值越大越相关
--计算相关系数----CV_TM_CCOEFF--值越大越相关
--计算平方不同归一化----CV_TM_SQDIFF_NORMED --值越小越相关
--计算相关性归一化----CV_TM_CCORR_NORMED --值越大越相关
--计算相关系数归一化----CV_TMCCOEFF_NORMED --值越大越相关
[API]:|matchTemplate(InputArray image, InputArray templ, OutputArray result, int method, InputArray mask=noArray())
----InputArray image--待搜索的图像,且图像必须为8-bit或32-bit的浮点型图像
----InputArray templ--用于进行模板匹配的模板图像,类型和原图像一致,但是尺寸不能大于原图像
----OutputArray result--模板搜索结果输出图像,必须为单通道32-bit位浮点型图像,如果图像尺寸是WxH而template尺寸是wxh,则此参数result一定是(W-w+1)x(H-h+1)
----int method--模板匹配计算类型,共6种(0, 1, 2, 3, 4, 5)
----InputArray mask=noArray()--图像匹配时用的掩膜板,必须和模板图像有相同的数据类型和尺寸
| minMaxLoc( const Mat& src, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, const Mat& mask=Mat())
----找到图像最小值,最大值并找到对应位置
----const Mat& src--InputArray类型的src,输入单通道数组(图像)
----double* minVal--double*类型的minVal,返回最小值的指针。若无须返回,此值置为NULL
----double* maxVal--double*类型的maxVal,返回最大值的指针。若无须返回,此值置为NULL
----Point* minLoc--Point*类型的minLoc,返回最小位置的指针(二维情况下)。若无须返回,此值置为NULL
----Point* maxLoc--Point*类型的maxLoc,返回最大位置的指针(二维情况下)。若无须返回,此值置为NULL
----const Mat& mask=Mat()--InputArray类型的mask,用于选择子阵列的可选掩膜
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
20、轮廓发现
----轮廓发现(find contour):在图像边缘提取的基础上寻找对象轮廓的方法,因此边缘提取的阈值选定会影响最终轮廓发现结果
[步骤]:----输入图像转为灰度图像
----使用canny进行边缘提取,转为二值图像
----使用findContours寻找轮廓
----使用drawContours绘制轮廓
[API]:|findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());
----发现轮廓
----InputOutputArray image---image可以是单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像
----OutputArrayOfArrays contours---contours 定义为“vector<vector<Point>> contours”,是一个向量,并且是一个双重向量,
向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓,
有多少轮廓,向量contours就有多少元素
----OutputArray hierarchy---hierarchy,定义为“vector<Vec4i> hierarchy”,Vec4i是Vec<int,4>的别名,定义了一个“向量内每一个元素包含了4个int型变量”的向量
---hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第 i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号
----int mode---int型的mode,定义轮廓的检索模式
---CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
---CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到
---CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
---CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
----int method---int型的method,定义轮廓的近似方法
---CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
---CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留
---CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
----Point offset=Point()---Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加
上该偏移量,并且Point还可以是负值
|drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point())
----绘制轮廓,在findContours的基础上对轮廓数据进行绘制显示
----InputOutputArray image--image表示目标图像
----InputArrayOfArrays contours--contours表示输入的轮廓组,每一组轮廓由点vector构成
----int contourIdx--contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓
----const Scalar& color--color为轮廓的颜色
----int thickness--thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部
----int lineType--lineType为线型
----InputArray hierarchy=noArray()--拓扑结构图
----int maxLevel=INT_MAX--最大层数,0表示只绘制外部轮廓,1表示绘制内外轮廓
----Point offset=Point()--轮廓位移,可选
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21、凸包(Convex Hull)
----包含点集合S中所有点的最小凸多边形(凸多边形中任意两点连线仍在该多边形中)称为凸包
----graham扫描算法:1、找到y轴方向值最小的点,从该点开始p0开始连接
2、每次连接后的线必须是逆时针方向,下一步连接如果使得线的变化方向变为顺时针则该点不属于凸包顶点集合的一部分
[API]:|void convexHull(InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true)
----InputArray points--得到的点集,一般是用图像轮廓函数求得的轮廓点
----OutputArray hull--输出的是凸包的二维xy点的坐标值,针对每一个轮廓形成的
----bool clockwise = false--表示凸包的方向,顺时针或者逆时针
----bool returnPoints = true--表示返回点还是点地址的索引
[步骤]:----首先图像由RGB转为灰度图
----再转为二值图像
----通过发现轮廓得到候选点
----凸包API调用
----绘制显示
[说明]:不要指望拿到一个API就可以完成像人脸识别等复杂的操作,要预先进行各种处理才能达到目标
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
22、轮廓周围绘制矩形和圆形
[API]:|approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
----基于RDP算法实现,目的是减少多边形轮廓点数
----InputArray curve:一般是由图像的轮廓点组成的点集
----OutputArray approxCurve:表示输出的多边形点集
----double epsilon:主要表示输出的精度,就是另个轮廓点之间最大距离数,5,6,7,,8
----bool closed:表示输出的多边形是否封闭
|boundingRect(InputArray points)
----得到轮廓周围最小矩形,左上角和右下角坐标共同绘制一个矩形
|minArrayRect(InputArray points)
----得到一个旋转的矩形
|minEnclosingCircle(InputArray points, Point&2f center, float& radius)
----画出一个圆
----Point&2f center--圆心
----float& radius--半径
|fitEllipse(InputArray points)
----得到椭圆
[步骤]:----图像变为二值图像
----发现轮廓,找到图像轮廓
----通过相关API在轮廓点上找到最小包含矩形和圆,旋转矩形和圆
----绘制它们
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
23、图像矩(moments)
----对于二值图像轮廓计算图像矩提取特征,有7个HU矩,各种阶数的矩都可以提取
----图像矩:|几何矩:M(i, j) = sum_(x, y){P(x, y) * (x^i) * (y^j)}
--几何矩就是把点(x, y)处P(x, y)像素值乘以(x^i) * (y^j),再把每一个像素算出的值求和
--这里(i + j)之和就是几何矩的阶数
|中心矩:mu(i, j) = sum_(x, y){P(x, y) * [(x - x_)^i] * [(y - y_)^j]}
--x_以及y_是它的中心质点
--这里(i + j)之和就是几何矩的阶数
|中心归一化矩:yu(i, j) = mu(i, j) / mu(0, 0)
|HU矩:利用二阶和三阶构造7个中心归一化距,在连续图像条件下,保持平移、缩放、旋转不变
--M1 = yu(2, 0) + yu(0, 2)
--M2 = [yu(2, 0) - yu(0, 2)]^2 + 4 * yu(1, 1)^2
--M3 =
--M4 =
--M5 =
--M6 =
--M7 =
[API]:|moments(InputArray array, bool binaryImage = false)
----计算图像中的中心矩(最高到三阶)
----HuMoments()用于由中心矩计算Hu矩.同时配合函数contourArea函数计算轮廓面积和arcLength来计算轮廓或曲线长度
----array:输入数组,可以是光栅图像(单通道,8-bit或浮点型二维数组),或者是一个二维数组(1 X N或N X 1),二维数组类型为Point或Point2f
----binaryImage:默认值是false,如果为true,则所有非零的像素都会按值1对待,也就是说相当于对图像进行了二值化处理,阈值为1,此参数仅对图像有效
|contourArea(InputArray contour, bool oriented = false)
----计算轮廓面积
----contour:是一个向量,二维点,可以是vector或Mat类型
----oriented:有默认值false,面向区域标识符,如果为true,该函数返回一个带符号的面积,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性可以根据面积的符号来确定轮廓的位置。如果是默认值false,则面积以绝对值的形式返回
|arcLength(InputArray curve, bool closed)
----用于计算封闭轮廓的周长或曲线的长度
----curve:输入二维点集,可以是vector或Mat类型
----closed:曲线是否封闭的标志位,true则封闭否则不封闭
[步骤]:--提取图像边缘
--发现轮廓
--计算每个轮廓对象的矩
--计算每个轮廓对象的弧长、中心、面积
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
24、点多边形测试
----测试一个点是否在给定的多边形内部,边缘或者外部
[API]:|double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
----返回数据类型是double
----InputArray contour--输入的轮廓
----Point2f pt--测试点
----bool measureDist--是否返回距离值,如果是false,1表示在内面,0表示在边界上,-1表示在外部,true返回实际距离
[演示代码步骤]:
----创建一张400 * 400的单通道图片 Mat::zeros(400, 400, CV_8UC1)
----画一个6边形的区域
----发现轮廓
----对图像中所有像素点进行点多边形测试,得到距离,归一化显示
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
25、基于距离变换和分水岭的图像分割
----图像分割:(Image Segmentation)分割算法分为无监督(大多数)和有监督
----距离变换和分水岭:
----距离变换:1、不断腐蚀和膨胀得到 2、基于倒角距离
----分水岭:基于浸泡理论
[说明]:以上举例算法是最常见的,深入还需学习
[API]:|void::distanceTransform(InputArray src, OutputArray dst, int distanceType, int maskSize, int labelType = DIST_LABEL_CCOMP)
----可用于实现目标细化、骨架提取、形状插值及匹配、粘连物体分离等,变换结果为灰度图像也是距离图像,每个点灰度值为该点举例背景的最短距离
----InputArray src:输入的图像,一般为二值图像
----OutputArray dst:输出的图像为8位或者32位浮点数,单一通道,大小与输入图像一致
----int distanceType:所用的求解距离的类型 DIST_L1 / DIST_L2
----int maskSize:距离变换掩模的大小,3×3 mask 或者5×5 mask
|watershed(InputArray image, InputOutputArray markers)
----
----InputArray image:
----InputOutputArray markers:
[处理步骤]:--将白色背景变成黑色,为后面的变换做准备
--使用filter2D和拉普拉斯算子实现图像对比度提高,sharp
--转为二值图像,threshold
--距离变换
--将距离变换结果归一化至0-1之间
--使用阈值再次二值化,得到标记
--腐蚀得到每个peak,erode
--发现轮廓,findContours
--绘制轮廓,drawContours
--分水岭变换,watershed
--对每个分割区域着色,输出结果