dogpi / opencv_projects

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

INCLUDEPATH += /usr/local/include \
               /usr/local/include/opencv4 \
               /usr/local/include/opencv4/opencv2

LIBS += /usr/local/lib/libopencv_highgui.so \
        /usr/local/lib/libopencv_core.so    \
        /usr/local/lib/libopencv_imgproc.so \
        /usr/local/lib/libopencv_imgcodecs.so \
        /usr/local/lib/*.so

opencv_001:
	掩膜操作(提高对比度)
		手动掩膜
		使用fliter2D进行掩膜操作
	总结:filter2D效率更高。
opencv_002:
	Mat相关操作:
		拷贝,复制,Scalar,指针操作,色域转换,定义小矩阵
opencv_003:
	对像素点进行操作
opencv_004:
	addWeighted图像融合
opencv_005:
	对每个像素点进行修改,提高图像的亮度,或降低图像的亮度。
opencv_006:
	基本几何形状绘制,文字显示
opencv_007:
	blur均值模糊(滤波):取所有像素的平均值赋值给当前像素
	GaussianBlur高斯模糊(滤波):均值滤波的kernel值为
			[1,1,1]
			[1,1,1]
			[1,1,1]
			        高斯滤波的kernel值为
			x = -2 w = 0.05
			x = -1 w = 0.15
			x = 0  w = 0.6
			x = 1  w = 0.15
			x = 2  w = 0.05
opencv_008:
	medianBlur中值滤波:对椒盐噪声有很好的抑制作用
			对kernel覆盖的像素进行排序,把中间值赋值给中间像素,就会去除小的干扰
	bilateralFilter双边滤波 :保留图像梯度(轮廓),当有边界时中心的像素值很大,周围的像素值很小,可能会覆盖掉像素的边界特征。双边滤波可以设置阈值,当超过阈值后,就保留当前的像素值,否则就进行高斯滤波。 
opencv_009:
	Mat kernel = getStructuringElement(int shape,Size ksize,Point anchor);
	腐蚀:数值小的像素取代数值大的像素(暗的像素变多)
	膨胀:数值大的像素取代数值小的像素(亮的像素变多)
opencv_010:
	形态学操作:
		膨胀,腐蚀
		形态学梯度(膨胀-腐蚀)
		开操作(先腐蚀后膨胀:去除小亮点):先腐蚀去除小的亮点,大的要保留的亮色图像也会被深色覆盖部分,膨胀操作会使面积变小的亮色恢复原有大小。
		闭操作(先膨胀后腐蚀:去除小黑点)、
		顶帽(开操作-原图像)
		黑帽(闭操作-原图像)
opencv_011:
	形态学操作,提取水平与垂直线
	1、读取图像
	2、转为灰度图像
	3、转为二值图像(将要提取的线设置为前景色白色,背景为黑色)
	4、创建水平提取算子kernel_h,创建垂直提取算子kernel_v
	5、先腐蚀,后膨胀,或直接使用morphologyEx进行开操作。
opencv_012:
	上采样和降采样
	高斯不同(DOG):对一个图像进行一次高斯滤波,得到g1,再对g1进行高斯滤波得到	g2,g1-g2结果就是DOG。subtract(g1,g2,output_image,Mat());
opencv_013:
	基本阈值操作
	阈值类型:
		5种阈值处理方法
		1、THRESH_BINARY阈值二值化
		2、THRESH_BINARY_INY阈值反二值化
		3、THRESH_TRUNC截断(超过阈值的设为阈值,没超过的保持不变)
		4、THRESH_TOZERO阈值取零(超过阈值的保持不变,没超过阈值的取0)
		5、THRESH_TOZERO_INV(超过阈值的取0,没超过阈值的保持不变)	
		2种阈值寻找方法
		THRESH_OTSU 自动寻找合适的阈值,设置的阈值不再起作用(不用手动设置阈值)
		用法:用|或运算符与5种方法中的一种配合使用
		THRESH_TRIANGLE反二值化阈值
opencv_014:
	自定义线性滤波:
		kernel中心位置就是锚点
		卷积如何工作:把kernel放到像素数组上,求锚点周围覆盖的像素乘积之和(包括锚点),用来替换锚点覆盖下的像素的值,称为卷积处理。    
		                                                                                       
		常见算子:
		Robert算子:
		[+1,  0
		    0,-1]
		[  0,+1
		  -1,  0]
		Sonel算子:
		[-1,0,1
		 -2,0,2
		 -1,0,1]
		[-1,-2,-1
		   0, 0, 0
		   1, 2, 1]
		拉普拉斯算子:
		[ 0,-1, 0
		 -1, 4,-1
		   0,-1,0]
		Sobel算子和拉普拉斯算子用来寻找图像的梯度和边缘。
opencv_015:
	处理边缘:
		BORDER_CONSTANT:填充边缘用指定像素值
		BORDER_REPLICATE:填充边缘像素用已知的边缘值
		BORDER_WRAP:用另外一边的像素值来补偿填充
	给图像添加边缘:
		copyMakeBorder(Mat src,Mat dst,int top,int bottom,int left,int right,int borderTpe,Scalar value)
		卷积操作的函数可以指定边缘填充的类型:
			GaussianBlur(src,dst,Size(3,3),0,0,BORDER_WRAP);
opencv_016:
	卷积应用:图像边缘提取,计算图像像素的分布,求一阶导数,导数最大的地方就是边缘。
	图像边缘提取:
		边缘是什么——是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
		如何捕捉/提取边缘——对图像求一阶导数delta=f(x)-f(x-1),delta越大,说明像素在X方向上变化越大,边缘信号越强。
	Sobel算子提取边缘:
		水平梯度:Gx = kernel_x*I
		垂直梯度:Gy = kernel_y*I
		最终梯度:
				G = Square(Gx2+Gy2) ===>L1
				G = |Gx| + |Gy|            ===>L2  近似求解,速度快
		Sobel(
			inputArray Src,
			outputArray dst,
			int depth,		// 图像深度,-1会自动设置
			int dx,			// x方向求导的阶数
			int dy,			// y方向求导的阶数
			int ksize,		// kernel的大小,必须是奇数。
			double scale = 1,	
			double delta = 0,
			int borderType = BORDE_DEFAULT
		)
	Laplance算子二阶求导获取图像边缘:
		一阶导数的极大值点是边界,在二阶导数中过0点。
		1、高斯模糊去噪声
		2、转换为灰度图像
		3、拉普拉斯二阶导数计算
		4、取绝对值
		5、显示结果
opencv_017:

	Canny边缘检测:
		算法介绍:共五步
			1、高斯模糊 GaussianBlur
			2、灰度转换 cvtColor
			3、计算梯度 Sobel/Scharr
			4、非最大信号抑制:根据比较方向比较当前像素与左右或上下元素的值,如果该值是最大值则保留,不是最大值则置0;
			5、高低阈值输出二值图像:T1,T2为阈值,凡是高于T1的都保留,凡是小于T2的都丢弃。从高于T1的像素出发,凡是大于T2而且相互连接的,都保留。最终输出二值图像。推荐高低阈值比为T1:T2 = 3:1 / 2:1,其中T1为高阈值,T2为低阈值。
		Canny(
			inputArray src,		// 输入8-bit图像(0-255)也就是灰度图像
			outputArray dst,		//输出边缘图像,一般为二值图像,背景是黑色
			double threshold1,		//低阈值
			double threshold2,		//高阈值(低阈值大2倍或3倍)
			int aptertureSize,		//Sobel算子的Size,通常是3*3,取值3
			bool L2gradient		// 选择true表示是L2来归一化,否则使用L1归一化
		)
opencv_018:
	霍夫变换——直线检测:
		对于所有给出的点,投影到极坐标上,r = xcosɵ+ysinɵ,根据不同的角度,可以得到一条曲线。每个点都能得到一条曲线,如果多个点投影的曲线交于一点,说明这些点在同一条直线上,根据ɵ,r可以推算出直线的位置。
	对于任意一条直线上的点来说,变换到极坐标中,从[0,360]空间,可以得到r的大小。属于同一条直线上的点在极坐标(r,ɵ)必然在一点上有最强的信号出现,根据此反算到平面坐标中就可以得到直线上各点的像素坐标。从而得到直线。
	如果把图像转换成二值图像,前景色为白色,投影到极坐标上,最白的点就是最强信号,在同一直线上的点的累加。
	HoughLines(
		inputArray src,
		outputArray lines,
		double rho,		//生层极坐标时,像素扫描的步长
		double theta,		//生成极坐标时,角度步长,一般取CV_PI/180.0
		int threshold,		//阈值,当点数超过该值时才被看做是直线
		…...
	) 输出(r,ɵ)
	HoughLinesP()输出直线(x0,y0,x1,y1)

	霍夫变换——圆检测:
		对一个像素点,根据r和 ɵ,逐步增加,多个相同大小的圆交于一点,说明这些像素在同于个圆上,交点就是圆的圆心
		HoughCircles(
			inputArray image,	// 8位灰度图像
			outputArray circles,	//输出发现结果
			int method,		// 方法-HOUGH_GRADIENT
			double dp,		// 1
			double mindist,	//10 最短距离-可以分辨是两个圆,否则认为是同心圆
			double param1,	//
			double param2,	//中心点累加阈值
			int minradius,		//最小半径
			int maxradius		//最大半径
		)
opencv_019:	
	remap:像素重映射
map_x.create(src.size(),CV_32FC1);
map_y.create(src.size(),CV_32FC1);
remap(src,dst,map_x,map_y,INTER_LINEAR,BORDER_CONSTANT,Scalar(0,255,0));
// remap的映射表
void update_map(){
    for(int row=0;row<src.rows;row++){
        for(int col=0;col<src.cols;col++){
            switch (num) {
            case 0:// 图像缩小为原来的二分之一,相当于降采样
                if(col>=src.cols*0.25&&col<=src.cols*0.75&&row>=src.rows*0.25&&row<=src.rows*0.75){// 在显示窗口的中心显示缩小后的图片,没有没有被图像覆盖的地方用0覆盖
                    // 保留偶数行和偶数列的像素
			  // 映射表里的元素是该位置应该对应原图像中像素的位置
                    map_x.at<float>(row,col) = 2*(col-src.cols*0.25);
                    map_y.at<float>(row,col) = 2*(row-src.rows*0.25);
                }else {
                    map_x.at<float>(row,col) = 0;
                    map_y.at<float>(row,col) = 0;
                }
                break;
            case 1:// 图像关于y轴翻转
                map_x.at<float>(row,col) = src.cols-col;
                map_y.at<float>(row,col) = row;
                break;
            case 2:// 图像关于x轴翻转
                map_x.at<float>(row,col) = col;
                map_y.at<float>(row,col) = src.rows-row;
                break;
            case 3:// 图像关于xy轴翻转
                map_x.at<float>(row,col) = src.cols-col;
                map_y.at<float>(row,col) = src.rows-row;
                break;
            }
        }
    }
}
opencv_020:
	直方图:对图像中的像素值进行统计,显示成直方图。
		直方图反应了图像灰度分布情况,是图像的统计学特征。
	直方图均衡化:是一种提高图像对比度的方法
			使用remap将图像灰度从一个分布映射到另一个分布。
			equalizeHist(src,dst);//输入为8位的单通道图像。
opencv_021:
	直方图计算:
		dims表示维度,对灰度图像来说只有一个通道,dims=1
		bins 表示在维度中子区域大小划分,bins=256,划分为256个级别
		range表示值的阈值,灰度值范围为[0,255]之间
	
	把多通道图像分为多个单通道图像,都是灰度图像,但灰度的值对应的是每个通道原有值的大小	
	split(
		const Mat& src,	// 输入图像
		Mat * mvbegin	// 输出图像数组
	)
	calcHist(
		const Mat* images,	// 输入图像指针
		int images,		//图像数目
		const int *channels, 	// 通道数
		inputArray mask,	// 输入mask,可选
		outputArray hist,	// 输出直方图数据
		int dims,		// 维数
		const int * histsize,	// 直方图级数
		const float* range,	// 值域范围
		bool uniform,		// true by default
		bool accumulate	// false by default
	)
	cvRound(float/double/int);//将浮点数四舍五入到最接近的整数
	
	normalize:
	
void cv::normalize 
(
InputArray src, 
InputOutputArray dst, 
double alpha = 1, 
double beta = 0, 
int norm_type = NORM_L2, 
int dtype = -1, 
InputArray mask = noArray() 
)


Python:dst=cv.normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]])

#include <opencv2/core.hpp>
Normalizes the norm or value range of an array. 
The function cv::normalize normalizes scale and shift the input array elements so that 
∥dst∥Lp=alpha
(where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; or so that 
minIdst(I)=alpha,maxIdst(I)=beta
when normType=NORM_MINMAX (for dense arrays only). The optional mask specifies a sub-array to be normalized. This means that the norm or min-n-max are calculated over the sub-array, and then this sub-array is modified to be normalized. If you want to only use the mask to calculate the norm or min-max but modify the whole array, you can use norm and Mat::convertTo.
In case of sparse matrices, only the non-zero values are analyzed and transformed. Because of this, the range transformation for sparse matrices is not allowed since it can shift the zero level.
Possible usage with some positive example data: 
vector<double> positiveData = { 2.0, 8.0, 10.0 };
vector<double> normalizedData_l1, normalizedData_l2, normalizedData_inf, normalizedData_minmax;
// Norm to probability (total count)
// sum(numbers) = 20.0
// 2.0 0.1 (2.0/20.0)
// 8.0 0.4 (8.0/20.0)
// 10.0 0.5 (10.0/20.0)
normalize(positiveData, normalizedData_l1, 1.0, 0.0, NORM_L1);
// Norm to unit vector: ||positiveData|| = 1.0
// 2.0 0.15
// 8.0 0.62
// 10.0 0.77
normalize(positiveData, normalizedData_l2, 1.0, 0.0, NORM_L2);
// Norm to max element
// 2.0 0.2 (2.0/10.0)
// 8.0 0.8 (8.0/10.0)
// 10.0 1.0 (10.0/10.0)
normalize(positiveData, normalizedData_inf, 1.0, 0.0, NORM_INF);
// Norm to range [0.0;1.0]
// 2.0 0.0 (shift to left border)
// 8.0 0.75 (6.0/8.0)
// 10.0 1.0 (shift to right border)
normalize(positiveData, normalizedData_minmax, 1.0, 0.0, NORM_MINMAX);
Parameters
src input array. 
dst output array of the same size as src . 
alpha norm value to normalize to or the lower range boundary in case of the range normalization.在范围归一化的情况下,要归一化到下限边界的标准值。 
beta upper range boundary in case of the range normalization; it is not used for the norm normalization. 范围归一化的情况下的范围上限; 它不用于规范归一化。
norm_type normalization type (see cv::NormTypes). 
dtype when negative, the output array has the same type as src; otherwise, it has the same number of channels as src and the depth =CV_MAT_DEPTH(dtype). 
mask optional operation mask. 

opencv_022:
	直方图比较:
		相关性比较(Correlation)
		Chi-Square(卡方比较)
		Intersection(十字交叉性)
		Bhattacharyya distance(巴氏距离)
	步骤:
      		a.先用cvtColor()把图像从RGB色彩空间转换到HSV色彩空间;
        	b.计算图像的直方图,然后归一化到[0~1]之间,用到函数 calcHist() 和 normalize() ;
        	c.使用上述的四种方法之一进行比较,用到函数compareHist()。
opencv_023:
	反射投影:
        原理:
            函数cv :: calcBackProject计算直方图的反向投影。
            也就是说,类似于calcHist,该函数在每个位置(x,y)收集输入图像中所选通道的值,并找到相应的直方图bin。
            但是该函数不是增加它,而是读取bin值,按比例缩放它,并将其存储在backProject(x,y)中。
            在统计方面,该函数根据直方图表示的经验概率分布计算每个元素值的概率。
            例如,查看如何在场景中查找和跟踪明亮的对象:跟踪之前,将对象显示给相机,使其几乎覆盖整个画面。
            计算色调直方图。直方图可能具有很强的最大值,对应于对象中的主要颜色。
            跟踪时,请使用该预先计算的直方图计算每个输入视频帧的色相平面的反投影。
            限制背投阈值以抑制较弱的色彩。抑制颜色饱和度不足且像素太暗或太亮的像素也可能是有意义的。
            在结果图片中找到连接的组件,然后选择最大的组件。
        步骤:
            1、是图像转换到HSV色域空间
            2、取出HSV空间的H通道进行calcHist,对直方图结果进行normalize
            3、对归一化后的结果进型calcBackProject,得到反向投影图像。
opencv_024:
	模板匹配(template match):
		模板匹配就是在整个图像区域发现与给定图像匹配的小块区域。
		所以模板匹配首先需要一个模板对象T(给定的子图像),另外需要一个待检测的图像-源图像S,工作方法就是在待检测的图像上,从左到右,从上到下计算模板与子图像的匹配度,匹配成都越大,两者形同的可能性越大。
	匹配算法:
		归一化平方不同(值越小越相关,0表示相同)
		归一化相关性(1相关0不相关)
		归一化相关系数(1相关0不相关)
	matchTemplate(
		inputArray image,	//源图像,必须是8位或32位浮点数图像
		inputArray templ,	//模板图像,类型与输入图像一致
		outoutArray result,	//输出结果,必须是单通道32位浮点数,假设源图像大小为W*H,模板图像大小w*h,则结果必须为W-w+1,H-h+1的大小
		int method,		// 使用的匹配方法
		inputArray mask=noArray()
	)
opencv_025:
	轮廓发现:
		轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现结果。
	发现轮廓	
	findContours(
		inputArray binImage,		// 输入图像
		outputArray contours,		//全部轮廓
		outputArray hierachy,		//
		int mode,			// 轮廓返回的模式
		int method,			//发现方法
		Point offset=Point()		//轮廓像素的位移,默认为(0,0),没有位移
	)
第三个参数:hierarchy,定义为“vector<Vec4i> hierarchy”,先来看一下Vec4i的定义:
	typedef  Vec<int, 4>   Vec4i;
	Vec4i是Vec<int,4>的别名,定义了一个“向量内每一个元素包含了4个int型变量”的向量。
	所以从定义上看,hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。
	向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。
	hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0]~hierarchy[i][3],分别表示第 i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个 轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1。
第四个参数:int型的mode,定义轮廓的检索模式:
	取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
	取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到
	取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
	取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
第五个参数: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偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值!

	绘制轮廓
	drawContours(
		inputoutputArray binimg,
		outputArray contours,	//全部发现的轮廓对象
		int contourIdx,//轮廓索引号
		const Scalar& color,//绘制时的颜色
		int tickness,//线的宽度
		int linetype,
		inputArray hierarchy,
		int maxlevel,//	最大层数
		Point offset=Point()//轮廓位移
	)	
	步骤:
		1、canny轮廓提取
		2、findContours()发现轮廓
		3、drawContours()绘制轮廓
opencv_026:
	凸包Convex Hull:
		在一个多边形边缘或内部任意两点的连线都包含在多边形边界或内部。
		包含点集合S中所有点的最小凸多边形称为凸包。
	如何找到凸包:
		Graham扫描算法:
			首先选择Y方向最低的点作为起始点p0,从p0开始极坐标扫描,依次添加p1...pn(排序顺序是根据极坐标的角度大小,逆时针方向),对每个点pi来说,如果添加pi到凸包导致一个左转向(逆时针方法)则添加该点到凸包,反之如果导致一个右转(顺时针方向)删除该点从凸包中。
		ConvexHull(
			inputArray points,//输入候选点,来自findContours
			outputArray hull,//凸包
			bool clockwise,//default true顺指针方向
			bool returnPoint//true 返回点的个数,如果第二个参数是vector<Point>则自动忽略
		)
	步骤:
		1、读取图像,转为灰度图像,可以对灰度图像做适当的处理
		2、Canny发现边缘
		3、findContours提取轮廓
		4、convexHull发现凸包
		5、使用drawContours绘制轮廓与边缘opencv
opencv_027:
	轮廓周围绘制矩形或圆形框:
		1、提取边缘(也可以直接把灰度图像使用threshold转为二值图像用于发现轮廓)
		2、发现轮廓
		3、根据轮廓得到多边形apptoxPloyDP,圆minEnclosingCircle,矩形boundingRect
		4、绘制多边形drawContours、绘制圆circle、绘制矩形retangle
opencv_028:
	图像矩:Monents,相当于求图像的重心
	涉及api:moments、contourArea(计算轮廓面积)、arcLength(返回轮廓的周长)

opencv_029:
	点多边形测试:测试一个点是在一个多边形的内部还是外部或者是在边上。
	PointPolygonTest(
		inputArray contour,//输入轮廓
		Point2f pt,//测试点
		bool measureDist//是否返回距离值,如果false,1表示在内部,0表示在边上,-1表示在外部,true返回实际距离
	)
opencv_030:
	基于距离变换与分水岭的图像分割:
		图像分割:
			图像分割是图像处理中最重要的处理手段之一;图像分割的目标是将图像中像素根据一定的规则分为若干(N)个cluster集合,每个集合包含一类像素;根据算法分为监督学习方法和无监督学习方法,图像分割的算法多数是无监督学习算法-KMeans。
		距离变换:计算源图像每个像素到最近的零像素的距离。函数cv :: distanceTransform计算每个二进制图像像素到最近的零像素的近似或精确距离。 对于零图像像素,距离显然将为零。
			void cv::distanceTransform 	( 	
				InputArray  	src,	//输入的图像,一般为二值图像
				OutputArray  	dst,	//输出的图像
				OutputArray  	labels,
				int  	distanceType,	//所用的求解距离的类型CV_DIST_L1,CV_DIST_L2, CV_DIST_C
				int  	maskSize,	//距离变换掩模的大小,可以是 3 或 5. 对 CV_DIST_L1 或 CV_DIST_C 的情况,参数值被强制设定为 3, 因为 3×3 mask 给出 5×5 mask 一样的结果,而且速度还更快。
				int  	labelType = DIST_LABEL_CCOMP 
			) 	
		分水岭变换:
			void cv::watershed ( 	
				InputArray  	image,
				InputOutputArray  	markers 
			) 	
	处理流程:
		1、将白色背景变为黑色
		2、使用filter2D与拉普拉斯算子实现图像对比度提高
		3、转为二值图像
		4、距离变换
		5、对距离变换结果进行归一化处理到[0-1]之间
		6、使用阈值,再次二值化,得到标记
		7、腐蚀得到的每个标记
		8、发现轮廓
		9、绘制轮廓
		10、分水岭变换
		11、对每个分割区域着色
Mat::convertTo( 	
	OutputArray  	m,//输出矩阵 如果操作前它的大小或类型不正确,则会对其进行重新分配。
	int  	rtype,//所需的输出矩阵类型或深度,因为通道数与输入的数目相同; 如果rtype为负,则输出矩阵将具有与输入相同的类型。
	double  	alpha = 1,
	double  	beta = 0 
)const

void cv::filter2D 	( 	
		InputArray  	src,
		OutputArray  	dst,
		int  	ddepth,	//输出图像的相关类型CV_8U/CV_16U/CV_16S/CV_32F/CV_64F/-1output image will have the same depth as the source.
		InputArray  	kernel,
		Point  	anchor = Point(-1,-1),
		double  	delta = 0,
		int  	borderType = BORDER_DEFAULT 
	) 
总结:watershed函数有两个参数,第一个参数是CV_8UC3的图片,第二个元素markers是可以标记不同区域的种子。根据这个种子可以区分不同的区域,所以我们就通过距离变换然后腐蚀操作得到能够代表每个区域的markers。markers会在watershed完成后作为输出,区域之间的边界值为-1。每个区域的值是markers种子轮廓的值。所以大多数的操作都是为了获得markers是。
opencv_031:
	使用distanceTransform找到图形的重心,见opencv_029	


opencv_032:
	角点检测:
		角点检测是计算机视觉系统中用来获取图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中,也称为特征点检测。
		角点通常是被定义为两条边的交点,更严格地说法是,角点的局部邻域应该具有两个不同区域的不同方向上的边界。而实际应用中,大多数所谓的角点检测方法检测的都是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。
		另外,关于角点的具体描述可以有如下几种:
		-一阶导数(即灰度的梯度)的局部最大所对应的像素的点
		-两条及两条以上边缘的交点
		-图像中梯度值和梯度方向的变化率都很高的点
		-角点处的一阶导数最大,二阶导数为零,它指示了物体边缘变化不连续的方向。
	Harris corner 角点检测:
		harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精确度高。但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。
opencv_033:
	Shi-Tomasi 角点检测:
		Shi-Tomasi是Harris的改进版。
	void cv::goodFeaturesToTrack 	( 	
		InputArray  	image,
		OutputArray  	corners,//Output vector of detected corners. 
		int  	            maxCorners,//最大角点数,如果该值小于角点数,就取最大的maxCorner个角点。maxCorner<=0 all corner are returned。
		double  	qualityLevel,//该参数表征图像角的最低可接受质量。 参数值乘以最佳角质量度量,即最小特征值(请参见cornerMinEigenVal)或哈里斯函数响应(请参见cornerHarris)。 质量度量低于产品的角被拒绝。 例如,如果最佳角的质量量度= 1500,而qualityLevel = 0.01,则拒绝质量量度小于15的所有角。
		double  	minDistance,//返回的角之间的最小可能欧几里得距离。
		InputArray  	mask = noArray(),
		int  	            blockSize = 3,
		bool  	            useHarrisDetector = false,
		double  	k = 0.04 
	) 	
	void cv::goodFeaturesToTrack 	( 	
                               InputArray  	image,
		OutputArray  	corners,
		int  	            maxCorners,
		double  	qualityLevel,
		double  	minDistance,
		InputArray  	mask,
		int  	            blockSize,
		int  	            gradientSize,
		bool  	            useHarrisDetector = false,
		double  	k = 0.04 
	) 		
	1、加载图像
	2、转为灰度图像
	3、角点检测 goodFeaturesToTrack
	4、画出角点位置
opencv_034:
	自定义角点检测器:
		-基于Harris与Shi-Tomasi角点检测
		-首先通过计算矩阵M得到λ1λ2两个特征值,根据他们得到角点相应值
		-然后自己设置阈值实现计算出阈值得到有效相应值的角点位置
	API:
	计算图像块的特征值和特征向量以进行角点检测。
	void cv::cornerEigenValsAndVecs 	( 	
		InputArray  		src,
		OutputArray  	dst,//type CV_32FC(6),每个位置有6个元素(λ1,λ2,x1,y1,x2,y2),λ1λ2是特征值,x1y1是λ1的特征向量,x2y2是λ2的特征向量
		int  			blockSize,
		int  			ksize,
		int  			borderType = BORDER_DEFAULT 
	) 	
	计算用于角点检测的梯度矩阵的最小特征值。Tomasi不需要最大特征向量可以使用该函数计算最小特征向量。
	void cv::cornerMinEigenVal 	( 	
		InputArray  	src,
		OutputArray  	dst,
		int  	blockSize,
		int  	ksize = 3,
		int  	borderType = BORDER_DEFAULT 
	) 	
	步骤:
		1、加载图像
		2、转为灰度图像
		3、计算特征值特征向量
		4、根据特征值特征向量计算响应值(计算方法可以自定义,也可以使用karris或Shi-Tomasi的计算方法)
		5、标记角点位置

	Harris:响应计算公式dst(x,y)=detM(x,y)−k⋅(trM(x,y))2
opencv_035:
	亚像素级角点检测:
		如果我们进行图像处理的目的不是提取用于识别的特征点,而是进行集合测量,这通常需要更高的精度,而函数goodFeaturesToTrack()只能提供简单的像素的坐标值,也就是说,有时候会需要实数坐标值而不是整数坐标值。
		亚像素级角点检测的位置在摄像机标定、跟踪并重建摄像机的轨迹,或者重建被跟踪目标的三维结构时,是一个基本的测量值。
	寻找亚像素角点:cornerSubPix()函数
	void cornerSubPix(
		InputOutputArray image,//输入图像
		InputOutputArray corners,// 提供输入角点的初始坐标和精确的输出坐标
		Size winSize,// 搜索窗口的一半尺寸,若winSize=Siz(5,5),那么表示使用(5*2+1)*(5*2_1)=11*11大小的搜索窗口
		Size zeroZone,// 表示死区的一半尺寸。死区为不对搜索区的**位置做求和运算的区域,用来避免自相关矩阵出现的某些可能的奇异性。值为(-1,-1)表示没有死区。
		TermCriteria criteria	//  求角点的迭代过程的中值条件。即角点位置的确定,哟啊么迭代数大于某个设定值,或者是精确度达到某个设定值。 criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
	)
opencv_036:
	特征点检测
	SURF算法工作原理:
		1、选择图像中的POI(Points of interest)Hessian Matrix
		2、在不同的尺度空间发现关键点,非最大信号压制
		3、发现特征点方法、旋转不变性要求
		4、生成特征向量
	API:
		使用cv :: FeatureDetector接口来查找兴趣点。
		特别:使用cv :: xfeatures2d :: SURF及其函数
		cv :: xfeatures2d :: SURF :: detect来执行检测过程使用函数
		cv :: drawKeypoints绘制检测到的关键点

	cv::xfeatures2d::SURF::create(
		double  	hessianThreshold = 100,//SURF中使用的Hessian关键点检测器的阈值。
		int	  	nOctaves = 4,	//表示在四个尺度空间
		int	  	nOctaveLayers = 3,// 表示每个尺度空间的层数
		bool	  	extended = false,
		bool	  	upright = false 
	)
	
	void drawKeypoints( const Mat& image,
    		const vector<KeyPoint>& keypoints,
   		CV_OUT Mat& outImage,
      	const Scalar& color=Scalar::all(-1),
      	int flags=DrawMatchesFlags::DEFAULT
	);
	第一个参数image:原始图像,可以使三通道或单通道图像;
	第二个参数keypoints:特征点向量,向量内每一个元素是一个KeyPoint对象,包含了特征点的各种属性信息;
	第三个参数outImage:特征点绘制的画布图像,可以是原图像;
	第四个参数color:绘制的特征点的颜色信息,默认绘制的是随机彩色;
	第五个参数flags:特征点的绘制模式,其实就是设置特征点的那些信息需要绘制,那些不需要绘制,有以下几种模式可选:
  	DEFAULT:只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标。
  	DRAW_OVER_OUTIMG:函数不创建输出的图像,而是直接在输出图像变量空间绘制,要求本身输出图像变量就是一个初始化好了的,size与type都是已经初始化好的变量
  	NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
  	DRAW_RICH_KEYPOINTS:绘制特征点的时候绘制的是一个个带有方向的圆,这种方法同时显示图像的坐标,size,和方向,是最能显示特征信息的一种绘制方式。

opencv_037:
	SIFT特征检测:尺度不变特征变换。https://baike.baidu.com/item/SIFT/1396275#3
	SIFT特征检测关键特性:
		1、建立尺度空间,寻找极值
		2、关键点定位(寻找关键点准确位置与删除弱边缘)
		3、关键点方向指定
		4、关键点描述子
	cv::xfeature2d::SIFT::create(
		int  nfeatures = 0,
     		int  nOctaveLayers = 3,    --高斯金字塔乘积数
    		double contrastThreshold = 0.04,    --对比度
    		double edgeThreshold = 10,   --边缘阈值,一般默认10就行
     		double sigma = 1.6      
	)


opencv_038:
	HOG特征检测:通过计算局部区域的梯度方向直方图来构成特征。
		1、灰度图像转换
		2、梯度计算
		3、分网格的梯度方向直方图
		4、块描述子
		5、块描述子归一化
		6、特征数据与检测窗口
		7、匹配方法
	优点:
		(1)HOG表示的是边缘(梯度)的结构特征,因此可以描述局部的形状信息;
		(2)位置和方向空间的量化一定程度上可以抑制平移和旋转带来的影响;
		(3)采取在局部区域归一化直方图,可以部分抵消光照变化带来的影响;
		(4)由于一定程度忽略了光照颜色对图像造成的影响,使得图像所需要的表征数据的维度降低了;
		(5)而且由于这种分块分单元的处理方法,也使得图像局部像素点之间的关系可以很好得到表征。
	缺点:
		(1)描述子生成过程冗长,导致速度慢,实时性差;
		(2)很难处理遮挡问题;
		(3)由于梯度的性质,该描述子对噪点相当敏感。

	HOG和SIFT都是描述子,以及由于在具体操作上有很多相似的步骤,所以致使很多人误认为HOG是SIFT的一种,其实两者在使用目的和具体处理细节上是有很大的区别的。HOG与SIFT的主要区别如下:
	(1)SIFT是基于关键点特征向量的描述。
	(2)HOG是将图像均匀的分成相邻的小块,然后在所有的小块内统计梯度直方图。
	(3)SIFT需要对图像尺度空间下对像素求极值点,而HOG中不需要。
	(4)SIFT一般有两大步骤,第一个步骤对图像提取特征点,而HOG不会对图像提取特征点。

	cv::HOGDescriptor::HOGDescriptor 	( 	
		Size  	_winSize,//窗口大小
		Size  	_blockSize,//块大小 每个块中有blockSize×blockSize个cell
		Size  	_blockStride,//块步长
		Size  	_cellSize,//图像分割成每个大小为cellSize的块
		int  	_nbins,//把-180~180分为nbins个区域
		int  	_derivAperture = 1,
		double  	_winSigma = -1,
		HOGDescriptor::HistogramNormType  	_histogramNormType = HOGDescriptor::L2Hys,
		double  	_L2HysThreshold = 0.2,
		bool  	_gammaCorrection = false,
		int  	_nlevels = HOGDescriptor::DEFAULT_NLEVELS,
		bool  	_signedGradient = false 
	) 	
	HOGDescriptor(
		 Size _winSize, ---:窗口大小,即检测的范围大小,前面的64*128
       Size _blockSize,--- 前面的2*2的cell,即cell的数量,这里要填像素值Size(16,16)
       Size _blockStride,---每次block移动的步长,以像素计,为一个cell像素块大小
             		 Size _cellSize, ---cell的大小,前面的8*8
       int _nbins,     ----直方图的组数
        	int _derivAperture=1, --梯度计算的参数
      	double _winSigma=-1, --梯度计算的参数
              		int _histogramNormType=HOGDescriptor::L2Hys,---归一化的方法
              		double _L2HysThreshold=0.2,  
      	bool _gammaCorrection=false,    ---是否要伽马校正
               		int _nlevels=HOGDescriptor::DEFAULT_NLEVELS, 
      	bool _signedGradient=false
	)
	64*128像素的图片,cell大小为8*8,可以分为8*16个cell。步长为一个cell也就是8pix,块大小为2*2cell,可以分为7*15个块,9个bins。
	每个块有2*2个cell,有2*2个向量,7*15个块就有2*2*7*15个向量,又分9个bins,共有2*2*7*15*9=3780个向量。
opencv_039:
	HOG与行人检测
	
opencv_040:
	LBP(Local Binary Pattern,局部二值模式):
	原始的LBP算子定义为3*3,以邻域中心像素为阈值,相邻大8个像素的灰度值与邻域中心的像素值进行比较,若大于中心像素则该像素点的位置被标记为1,否则为0。这样3*3的邻域内可以产生8个值为0或1的数,将这8个数依次排列成一个二进制数字,这个二进制数就是中心像素的LBP值,LBP值共有28种可能,因此LBP值可以取0-255,也就是256种。
	44, 118,192			0,  1, 1
	32,   83,204 		--->	0,    , 1
	61, 174,250			0,  1, 1
	(01111100)10=124
    //转为灰度图像
    Mat gray_src;
    cvtColor(src,gray_src,COLOR_BGR2GRAY);
    Mat dst(Size(src.cols-2,src.rows-2),CV_8U);
    //计算LBP
    for(int row=1;row<gray_src.rows;row++){
        for(int col=0;col<gray_src.cols;col++){
            uchar center = gray_src.at<uchar>(row,col);
            //由于计算后的值在0-255之间,所以要使用uchar来保存最为合适
            uchar lbpcode = 0;
            lbpcode|=(gray_src.at<uchar>(row-1,col-1)>center)<<7;
            lbpcode|=(gray_src.at<uchar>(row-1,col)>center)<<6;
            lbpcode|=(gray_src.at<uchar>(row-1,col+1)>center)<<5;
            lbpcode|=(gray_src.at<uchar>(row,col+1)>center)<<4;
            lbpcode|=(gray_src.at<uchar>(row+1,col+1)>center)<<3;
            lbpcode|=(gray_src.at<uchar>(row+1,col)>center)<<2;
            lbpcode|=(gray_src.at<uchar>(row+1,col-1)>center)<<1;
            lbpcode|=(gray_src.at<uchar>(row,col-1)>center)<<0;
            // 不要直接把值赋值给gray_src,会影响下一次循环的值。
            // gray_src.at<uchar>(row,col) = lbpcode;
            dst.at<uchar>(row,col) = lbpcode;
        }
    }
OpenCV在这部分里包含一些类似标准c++、c里面的一些东西。
实用函数很接近<math.h>里的一些函数,很有意思,可以方便大家开发,有
计算向量角度的函数fastAtan2、
计算立方根的函数cubeRoot、
向上取整函数cvCeil、
向下取整函数cvFloor、
四舍五入函数cvRound。
注意cvCeil、cvFloor、cvRound和大家常用的ceil、floor、round函数略有不同,标准库函数返回值并不是int型的变量,必要时需强制转换,而OpenCV里面的取整函数返回值为int型。

双线性插值实现LBP
//对每个像素进行处理
    for(int row=radius_value;row<src.rows-2*radius_value;row++){
        for(int col=radius_value;col<src.cols-2*radius_value;col++){

            uchar center = gray_src.at<uchar>(row,col);
            uchar lbpcode=0;
            // 取8个点
            // 计算8个点的坐标
            for(int k=0;k<neighbors;k++){
                float x = row+static_cast<float>(radius_value*cos(2.0*CV_PI*k/neighbors));
                float y = col-static_cast<float>(radius_value*sin(2.0*CV_PI*k/neighbors));

                // 由于不是整数,要对取到的点进行双线性插值计算,取像素值
                // 要使用双线性插值计算就要得带点周围的4个整值点,也就是图像中真是存在的点
                // 对取到的点进行取整即可
                int x1 = static_cast<int>(floor(x));
                int x2 = static_cast<int>(ceil(x));
                int y1 = static_cast<int>(floor(y));
                int y2 = static_cast<int>(ceil(y));

                // 计算四个点(x1,y1),(x1,y2),(x2,y1),(x2,y2)的权重
                // 将坐标映射到0-1之间,不使用四个点直接计算权重是因为如果四个点相同,计算得带的权重就会是0,插值也会为0
                float tx = x-x1;
                float ty = y-y1;

                float w1 = (1-tx)*(1-ty);
                float w2 = tx*(1-ty);
                float w3 = (1-tx)*ty;
                float w4 = tx*ty;

                // 计算出8个点中一个的像素值
                float value = gray_src.at<uchar>(x1,y1)*w1+
                              gray_src.at<uchar>(x1,y2)*w2+
                              gray_src.at<uchar>(x2,y1)*w3+
                              gray_src.at<uchar>(x2,y2)*w4;
                lbpcode |=(value>center)<<(neighbors-k-1);
            }
            dst.at<uchar>(row-radius_value,col-radius_value) = lbpcode;
        }
    }
opencv_041:
	特征描述子与匹配:
		1、使用SURF发现关键件并计算特征描述子
		2、使用暴力匹配算法进行匹配
opencv_042:
	FLANN特征匹配:快速最邻逼近搜索

void cv::drawMatches	(	
	InputArray 	img1,
	const std::vector< KeyPoint > & 	keypoints1,
	InputArray 	img2,
	const std::vector< KeyPoint > & 	keypoints2,
	const std::vector< DMatch > & 	matches1to2,
	InputOutputArray 	outImg,
	const Scalar & 	matchColor = Scalar::all(-1),
	const Scalar & 	singlePointColor = Scalar::all(-1),
	const std::vector< char > & 	matchesMask = std::vector< char >(),
	DrawMatchesFlags 	flags = DrawMatchesFlags::DEFAULT 
)	
DrawMatchesFlags
Enumerator
DEFAULT 	
Output image matrix will be created (Mat::create), i.e. existing memory of output image may be reused. Two source image, matches and single keypoints will be drawn. For each keypoint only the center point will be drawn (without the circle around keypoint with keypoint size and orientation).

DRAW_OVER_OUTIMG 	
Output image matrix will not be created (Mat::create). Matches will be drawn on existing content of output image.

NOT_DRAW_SINGLE_POINTS 	
Single keypoints will not be drawn.

DRAW_RICH_KEYPOINTS 	
For each keypoint the circle around keypoint with keypoint size and orientation will be drawn.
opencv_043:
	平面图像识别:
		接着上个实例继续改进
		findHomography---找到匹配关键点之间的变换
		perspectiveTransform---映射点

opencv_044:
		AKAZE特征检测:
opencv_045:
		Brisk特征检测:
opencv_046:
		层叠分类器(级联分类器):
			CascadeClassifier对象;
opencv_047:
		Kmeans聚类方法:该算法是无监督聚类算法,它实现起来比较简单,聚类效果也不错,因此应用很广泛,
		原理:
			对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。
opencv_048:
	Kmeans分割图像(背景为纯色)
opencv_049:
	高斯混合模型(GMM):
		
opencv_050:
	GMM图像分割:
opencv_051:
	GrabCut:GrabCut是一种基于图割的图像分割方法。
该算法从用户指定的包围盒开始,利用高斯混合模型估计目标和背景的颜色分布。它用于在像素标签上构造马尔可夫随机场,能量函数优先选择具有相同标签的连接区域,并运行基于图割的优化来推断其值。由于此估计可能比从边界框中获取的原始估计更精确,因此重复此两步过程直到收敛。
用户可以通过指出错误的分类区域并重新运行优化来进一步修正估计。该方法还修正结果以保留边缘。
有几种开源实现可供使用,包括OpenCV(从2.1版开始)。


Exception:
	

terminate called after throwing an instance of 'cv::Exception'
what():  OpenCV(4.2.0) /home/dogpi/Downloads/opencv-4.2.0/modules/highgui/src/window.cpp:376: error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'imshow'
原因:1、可能是加载的图片路径错误,检查路径和文件名是否正确,在imread中
	2、可能是要显示的Mat没有进行初始化就进行赋值并显示,如下代码在没有对drawImge初始化时就赋值并显示就会报错。
Mat drawImage = Mat::zeros(canny_mat.size(),CV_8UC3);
    for(size_t i = 0;i<contours.size();i++){
        Scalar color = Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
        drawContours(drawImage,contours,(int)i,color);
        drawContours(drawImage,contours,(int)i,color);
    }
    imshow("result",drawImage);


terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.2.0) /home/dogpi/Downloads/opencv-4.2.0/modules/highgui/src/precomp.hpp:137: error: (-215:Assertion failed) src_depth != CV_16F && src_depth != CV_32S in function 'convertToShow'
显示的图像不能是CV_32S和CV_16F

terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.2.0) /home/dogpi/Downloads/opencv-4.2.0/opencv_contrib-4.2.0/modules/xfeatures2d/src/surf.cpp:1029: error: (-213:The function/feature is not implemented) This algorithm is patented and is excluded in this configuration; Set OPENCV_ENABLE_NONFREE CMake option and rebuild the library in function 'create'
原因:缺少OPENCV_ENABLE_NONFREE 模块
在opencv的根目录下找到CMakeList.txt文件,修改OCV_OPTION(OPENCV_ENABLE_NONFREE "Enable non-free algorithms" OFF)为
OCV_OPTION(OPENCV_ENABLE_NONFREE "Enable non-free algorithms" ON),然后重新编译即可

About


Languages

Language:C++ 81.0%Language:QMake 19.0%