4.5.实例应用

4.5.1 导向滤波

导向滤波能实现:双边滤波的边缘平滑;在检测到边缘附近

应用:图像增强、HDR压缩、图像抠图以及图像去雾等

 1 #include <iostream>  
 2 #include "opencv2/core/core.hpp"    
 3 #include "opencv2/highgui/highgui.hpp"    
 4 #include "opencv2/imgproc/imgproc.hpp"      
 5 using namespace std;  
 6 using namespace cv;   
 7 // 导向滤波器 
 8 cv::Mat guidedfilter( Mat &srcImage, Mat &srcClone, int r, double eps )   
 9 {  
10   // 转换源图像信息
11   srcImage.convertTo(srcImage, CV_64FC1);      
12   srcClone.convertTo(srcClone, CV_64FC1);   
13   int nRows = srcImage.rows;  
14   int nCols = srcImage.cols;   
15   cv::Mat boxResult; 
16   // 步骤一: 计算均值
17   cv::boxFilter(cv::Mat::ones(nRows, nCols, srcImage.type()),
18       boxResult, CV_64FC1, cv::Size(r, r));  
19   // 生成导向均值mean_I    
20   cv::Mat mean_I;  
21   cv::boxFilter(srcImage, mean_I, CV_64FC1, cv::Size(r, r));   
22   // 生成原始均值mean_p   
23   cv::Mat mean_p;  
24   cv::boxFilter(srcClone, mean_p, CV_64FC1, cv::Size(r, r)); 
25   // 生成互相关均值mean_Ip 
26   cv::Mat mean_Ip;  
27   cv::boxFilter(srcImage.mul(srcClone), mean_Ip, 
28       CV_64FC1, cv::Size(r, r));   
29   cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p); 
30   // 生成自相关均值mean_II 
31   cv::Mat mean_II;  
32   cv::boxFilter(srcImage.mul(srcImage), mean_II, CV_64FC1, cv::Size(r, r)); 
33   // 步骤二:计算相关系数   
34   cv::Mat var_I = mean_II - mean_I.mul(mean_I); 
35   cv::Mat var_Ip = mean_Ip - mean_I.mul(mean_p); 
36   // 步骤三:计算参数系数a,b 
37   cv::Mat a = cov_Ip/(var_I + eps);    
38   cv::Mat b = mean_p - a.mul(mean_I);  
39   // 步骤四:计算系数a,b均值    
40   cv::Mat mean_a;  
41   cv::boxFilter(a, mean_a, CV_64FC1, cv::Size(r, r));  
42   mean_a = mean_a / boxResult;     
43   cv::Mat mean_b;  
44   cv::boxFilter(b, mean_b, CV_64FC1, cv::Size(r, r));  
45   mean_b = mean_b / boxResult;   
46   //步骤五:生成输出矩阵 
47   cv::Mat resultMat = mean_a.mul(srcImage) + mean_b;  
48   return resultMat;  
49 }    
50 int main()  
51 {    
52     cv::Mat srcImage = cv::imread("..\images\flower3.jpg");
53     if(srcImage.empty())
54           return-1;
55     cv::Mat srcGray(srcImage.size(),CV_8UC1);  
56     cvtColor(srcImage,srcGray,CV_BGR2GRAY); 
57     // 通道分离 
58     vector<Mat> vSrcImage, vResultImage;  
59     split(srcImage,vSrcImage);
60     Mat resultMat;      
61     for(int i=0; i < 3; i++)    
62     {    
63         // 分通道转换成浮点型数据
64         Mat tempImage ; 
65         vSrcImage[i].convertTo(tempImage, CV_64FC1,1.0/255.0);  
66         Mat p = tempImage.clone();
67         // 分别进行导向滤波       
68         Mat resultImage = guidedfilter(tempImage, p, 4, 0.01);  
69         vResultImage.push_back(resultImage);        
70     } 
71     // 通道结果合并   
72     merge(vResultImage,resultMat);  
73     cv::imshow("srcImage", srcImage);  
74     cv::imshow("resultMat", resultMat);  
75     cv::waitKey(0);    
76     return 0;  
77 }
View Code

第1张图片:

参考链接:https://blog.csdn.net/gone_huilin/article/details/53223488

第2张图片:

 1 //////https://blog.csdn.net/qq_34784753/article/details/70229009?locationNum=12&fps=1
 2 #include <iostream>
 3 #include <opencv2corecore.hpp>
 4 #include <opencv2highguihighgui.hpp>
 5 #include <opencv2imgprocimgproc.hpp>
 6 
 7 using namespace cv;
 8 using namespace std;
 9 
10 //导向滤波器
11 Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps);
12 
13 int main()
14 {
15     Mat srcImage = imread("D:\小狗狗.jpg");
16     if (srcImage.empty())
17     {
18         cout << "读入图片错误!" << endl;
19         system("pause");
20         return -1;
21     }
22     //进行通道分离
23     //vector<Mat>vSrcImage, vResultImage;
24     Mat vSrcImage[3];
25     Mat vResultImage[3];
26     split(srcImage, vSrcImage);
27     Mat resultMat;
28     for (int i = 0; i < 3; i++)
29     {
30         //分通道转换成浮点型数据
31         Mat tempImage;
32         vSrcImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0);
33         Mat p = tempImage.clone();
34         //分别进行导向滤波
35         Mat resultImage = guidedfilter(tempImage, p, 4, 0.01);
36         //vResultImage.push_back(resultImage);
37         vResultImage[i] = resultImage.clone();
38     }
39     //通道结果合并
40     //merge(vResultImage, resultMat);
41     merge(vResultImage, 3, resultMat);
42     imshow("原图像", srcImage);
43     imshow("导向滤波后图像", resultMat);
44     waitKey(0);
45     return 0;
46 }
47 
48 Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps)
49 {
50     //转换源图像信息
51     srcImage.convertTo(srcImage, CV_64FC1);
52     srcClone.convertTo(srcClone, CV_64FC1);
53     int NumRows = srcImage.rows;
54     int NumCols = srcImage.cols;
55     Mat boxResult;
56 
57     //下面按照步骤进行导向滤波操作
58     /////////////////////////////////////////////////////////////
59     //步骤一:计算均值
60     boxFilter(Mat::ones(NumRows, NumCols, srcImage.type()),
61         boxResult, CV_64FC1, Size(r, r));
62     //生成导向均值mean_I
63     Mat mean_I;
64     boxFilter(srcImage, mean_I, CV_64FC1, Size(r, r));
65     //生成原始均值mean_P
66     Mat mean_P;
67     boxFilter(srcClone, mean_P, CV_64FC1, Size(r, r));
68     //生成互相关均值mean_IP
69     Mat mean_IP;
70     boxFilter(srcImage.mul(srcClone), mean_IP,
71         CV_64FC1, Size(r, r));
72     Mat cov_IP = mean_IP - mean_I.mul(mean_P);
73     //生成自相关均值mean_II
74     Mat mean_II;
75     //应用盒滤波计算相关均值
76     boxFilter(srcImage.mul(srcImage), mean_II, CV_64FC1, Size(r, r));
77     //步骤二:计算相关系数
78     Mat var_I = mean_II - mean_I.mul(mean_I);
79     Mat var_IP = mean_IP - mean_I.mul(mean_P);
80     //步骤三:计算参数系数a,b
81     Mat a = cov_IP / (var_I + eps);
82     Mat b = mean_P = a.mul(mean_I);
83     //步骤四:计算系数a,b的均值
84     Mat mean_a;
85     boxFilter(a, mean_a, CV_64FC1, Size(r, r));
86     mean_a = mean_a / boxResult;
87     Mat mean_b;
88     boxFilter(b, mean_b, CV_64FC1, Size(r, r));
89     mean_b = mean_b / boxResult;
90     //步骤五:生成输出矩阵
91     Mat resultMat = mean_a.mul(srcImage) + mean_b;
92     return resultMat;
93 }
View Code

https://blog.csdn.net/qq_34784753/article/details/70229009?locationNum=12&fps=1 

https://blog.csdn.net/kuweicai/article/details/78385871 

https://blog.csdn.net/baimafujinji/article/details/74750283

https://blog.csdn.net/huixingshao/article/details/42834939

4.5.2 图像污点修复

图像修补就是使用坏点周围的像素取代坏点,这样它看起来和周围像素就比较像了。

 1 //////https://blog.csdn.net/hb707934728/article/details/51980304?locationNum=8&fps=1
 2 //////运行程序出现2个窗口:原始图参考和原始图,在原始图窗口绘制污点完成后,按下按键1触发修复,后显示在修补后的效果图窗口
 3 //////terminal的提示非常棒!
 4 #include "opencv2/highgui/highgui.hpp"
 5 #include "opencv2/imgproc/imgproc.hpp"
 6 #include "opencv2/photo/photo.hpp"
 7 #include <iostream>
 8 using namespace cv;
 9 using namespace std;
10 
11 
12 //-----------------------------------【宏定义部分】-------------------------------------------- 
13 //  描述:定义一些辅助宏 
14 //----------------------------------------------------------------------------------------------
15 #define WINDOW_NAME0 "【原始图参考】"        //为窗口标题定义的宏 
16 #define WINDOW_NAME1 "【原始图】"        //为窗口标题定义的宏 
17 #define WINDOW_NAME2 "【修补后的效果图】"        //为窗口标题定义的宏 
18 
19 
20 //-----------------------------------【全局变量声明部分】--------------------------------------
21 //          描述:全局变量声明
22 //-----------------------------------------------------------------------------------------------
23 Mat srcImage0, srcImage1, inpaintMask;
24 Point previousPoint(-1, -1);//原来的点坐标
25 
26 
27                             //-----------------------------------【ShowHelpText( )函数】----------------------------------
28                             //          描述:输出一些帮助信息
29                             //----------------------------------------------------------------------------------------------
30 static void ShowHelpText()
31 {
32 
33     //输出一些帮助信息
34     printf("


	欢迎来到【图像修复】示例程序~
");
35     printf("
	请在进行图像修复操作之前,在【原始图】窗口中进行适量的绘制"
36         "

	按键操作说明: 

"
37         "		【鼠标左键】-在图像上绘制白色线条

"
38         "		键盘按键【ESC】- 退出程序

"
39         "		键盘按键【1】或【SPACE】-进行图像修复操作 

");
40 }
41 
42 
43 //-----------------------------------【On_Mouse( )函数】--------------------------------
44 //          描述:响应鼠标消息的回调函数
45 //----------------------------------------------------------------------------------------------
46 static void On_Mouse(int event, int x, int y, int flags, void*)
47 {
48     //鼠标左键弹起消息
49     if (event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON))
50         previousPoint = Point(-1, -1);
51     //鼠标左键按下消息
52     else if (event == CV_EVENT_LBUTTONDOWN)
53         previousPoint = Point(x, y);
54     //鼠标按下并移动,进行绘制
55     else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))
56     {
57         Point pt(x, y);
58         if (previousPoint.x < 0)
59             previousPoint = pt;
60         //绘制白色线条
61         line(inpaintMask, previousPoint, pt, Scalar::all(255), 5, 8, 0);
62         line(srcImage1, previousPoint, pt, Scalar::all(255), 5, 8, 0);
63         previousPoint = pt;
64         imshow(WINDOW_NAME1, srcImage1);
65     }
66 }
View Code

绘制污点图:

修复后图:

 1 ///////https://blog.csdn.net/dcrmg/article/details/53792061
 2 //////全区域阈值处理+Mask膨胀处理
 3 #include <imgprocimgproc.hpp>
 4 #include <highguihighgui.hpp>
 5 #include <photophoto.hpp>
 6 
 7 using namespace cv;
 8 
 9 int main()
10 {
11     Mat imageSource = imread("D:\图像污点修复.jpg");
12     if (!imageSource.data)
13     {
14         return -1;
15     }
16     imshow("原图", imageSource);
17     Mat imageGray;
18     //转换为灰度图
19     cvtColor(imageSource, imageGray, CV_RGB2GRAY, 0);
20     Mat imageMask = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));
21 
22     //通过阈值处理生成Mask
23     threshold(imageGray, imageMask, 240, 255, CV_THRESH_BINARY);
24     Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
25     //对Mask膨胀处理,增加Mask面积
26     dilate(imageMask, imageMask, Kernel);
27 
28     //图像修复
29     inpaint(imageSource, imageMask, imageSource, 5, INPAINT_TELEA);
30     imshow("Mask", imageMask);
31     imshow("修复后", imageSource);
32     waitKey();
33 }
View Code

原图: 

处理过后:

由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。

方法二、鼠标框选区域+阈值处理+Mask膨胀处理

方法三、鼠标划定整个区域作为修复对象

参考:https://blog.csdn.net/dcrmg/article/details/53792061

 https://blog.csdn.net/chuhang_zhqr/article/details/51069183

https://blog.csdn.net/qq_29540745/article/details/52563861

https://blog.csdn.net/zhangjunp3/article/details/80059769

4.5.3 旋转文本图像矫正

利用傅里叶变换中时域与频域的变换关系实现旋转文本图像矫正。

仿射变换需要获取图像的倾斜角度

旋转文本图像的明显特征是存在分行间隔,当文本图像旋转时,其频域的频谱也会随之旋转。根据这一特征来计算文本图像的DFT变换,DFT变换的结果是

霍夫变换、边缘检测等数字图像处理算法检测图像的旋转角度

1、图像DFT尺寸转换

2、DFT变换

3、频域中心移动

4、倾斜角检测

5、仿射变换

  1 #include <opencv2/core/core.hpp>
  2 #include <opencv2/imgproc/imgproc.hpp>
  3 #include <opencv2/highgui/highgui.hpp>
  4 #include <iostream>
  5 using namespace cv;
  6 using namespace std;
  7 
  8 //傅里叶变化模块
  9 Mat DFT(Mat srcImage)
 10 {
 11     //1.转换位灰度图
 12     Mat srcGray;
 13     cvtColor(srcImage, srcGray, CV_BGR2GRAY);
 14 
 15     //2.将输入图像延扩到最佳的尺寸,边界用0填充
 16     int nRows = getOptimalDFTSize(srcGray.rows);
 17     int nCols = getOptimalDFTSize(srcGray.cols);
 18 
 19     Mat padded;
 20     //BORDER_CONSTANT是填充是常数的意思,填充的数是后面的0
 21     copyMakeBorder(srcGray, padded, 0, nRows - srcGray.rows, 0, nCols - srcGray.cols, BORDER_CONSTANT, Scalar::all(0));
 22 
 23     //3.为傅里叶变换的结果(实部与虚部)分别存储空间
 24     Mat planes[] = { Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F) };
 25     Mat complexI;
 26     //将planes数组组合合并成一个多通道的数组complexI
 27     merge(planes, 2, complexI);//将两个数组合并成一个多通道的数组
 28 
 29                                //4.进行离散傅里叶变换
 30     dft(complexI, complexI);
 31     //5.将复数转化为幅值
 32     // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)
 33     split(complexI, planes);//将多通道数组complexI分解为几个单通道的数组
 34                             //magnitude(x,y,dst);dst=sqrt(x(I)^2+y(I)^2);
 35     magnitude(planes[0], planes[1], planes[0]);
 36     Mat magnitudeImage = planes[0].clone();//傅里叶变换的幅值矩阵
 37                                            //6.进行对数尺度缩放
 38     magnitudeImage += Scalar::all(1);//对幅值都加1
 39     log(magnitudeImage, magnitudeImage);
 40     //归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
 41     normalize(magnitudeImage, magnitudeImage, 0, 1, CV_MINMAX);
 42     //图像类型转换,为了下一步的霍夫直线检测做准备
 43     magnitudeImage.convertTo(magnitudeImage, CV_8UC1, 255, 0);
 44     imshow("magnitudeImage", magnitudeImage);
 45     //7.剪切与重分布幅度图象限
 46     //若有奇数行或者奇数列,进行频谱裁剪
 47     //magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));
 48     //重新排列傅里叶图像中的象限,使得原点位于图像中心
 49     int cx = magnitudeImage.cols / 2;
 50     int cy = magnitudeImage.rows / 2;
 51     Mat q0(magnitudeImage, Rect(0, 0, cx, cy));//ROI区域的左上
 52     Mat q1(magnitudeImage, Rect(cx, 0, cx, cy));//ROI区域的右上
 53     Mat q2(magnitudeImage, Rect(0, cy, cx, cy));//ROI区域的左下
 54     Mat q3(magnitudeImage, Rect(cx, cy, cx, cy));//ROI区域的右上
 55 
 56                                                  //交换象限(左上与右下进行交换)
 57     Mat temp;
 58     q0.copyTo(temp);
 59     q3.copyTo(q0);
 60     temp.copyTo(q3);
 61     //交换象限(右上与左下进行交换)
 62     q1.copyTo(temp);
 63     q2.copyTo(q1);
 64     temp.copyTo(q2);
 65     Point pt1, pt2;
 66     pt1.x = cx;
 67     pt2.x = cx;
 68     pt1.y = 0;
 69     pt2.y = magnitudeImage.rows;
 70 
 71     //往书上结果靠拢,去掉频域中心移动的横线和竖线,后面判断直线角度直接不需要
 72     //line(magnitudeImage, pt1, pt2, Scalar(0, 0, 0), 1, CV_AA);
 73 
 74     return magnitudeImage;
 75 }
 76 //倾斜角检测  返回检测到的倾斜角
 77 float AngleDetection(Mat srcImage)
 78 {
 79     int nRows = srcImage.rows;
 80     int nCols = srcImage.cols;
 81     Mat binaryMat;
 82     //对傅里叶变换之后的图像进行二值化处理
 83     //根据不同的图片情况可能需要调整这个固定阈值
 84     threshold(srcImage, binaryMat, 135, 255, CV_THRESH_BINARY);
 85     imshow("binaryMat", binaryMat);//显示二值图像
 86                                    //霍夫变换
 87     vector<Vec2f> lines;
 88     binaryMat.convertTo(binaryMat, CV_8UC1, 255, 0);
 89     //下面阈值可能也需要根据情况调整
 90     HoughLines(binaryMat, lines, 0.5, CV_PI / 180, 30, 0, 0);
 91     //检测线的个数
 92     cout << "lines.size:" << lines.size() << endl;
 93     //创建一张直线检测图形
 94     Mat houghMat(binaryMat.size(), CV_8UC3);
 95     //绘制线检测
 96     for (size_t i = 0; i < lines.size(); i++)
 97     {
 98         //根据直线参数表达式绘制相应的检测结果
 99         float rho = lines[i][0], theta = lines[i][1];
100         Point pt1, pt2;
101         double a = cos(theta), b = sin(theta);
102         double x0 = a*rho, y0 = b*rho;
103         pt1.x = cvRound(x0 + 1000 * (-b));
104         pt1.y = cvRound(y0 + 1000 * (a));
105         pt2.x = cvRound(x0 - 1000 * (-b));
106         pt2.y = cvRound(y0 - 1000 * (a));
107         line(houghMat, pt1, pt2, Scalar(255, 0, 0), 3, CV_AA);
108     }
109     //显示绘制的图
110     imshow("houghMat", houghMat);
111 
112     float theta2 = 0;
113     //检测线角度判断
114     //因为文本检测的时候有三条直线,一条水平,一条垂直,还有一条就是我们需要的直线
115     for (size_t i = 0; i < lines.size(); i++)
116     {
117         float ThetaTemp = lines[i][1] * 180 / CV_PI;
118         //找出我们需要的那条直线就退出循环
119         if (ThetaTemp > 0 && ThetaTemp < 90)
120         {
121             theta2 = ThetaTemp;
122             break;
123         }
124     }
125     //角度转换
126     float angelT = nRows*tan(theta2 / 180 * CV_PI) / nCols;
127     theta2 = atan(angelT) * 180 / CV_PI;
128     cout << "theta2:" << theta2 << endl;
129     return theta2;
130 }
131 
132 //旋转图像,可以使用仿射变换
133 Mat RotIamge(Mat &srcImage, float Angle) //旋转角度然后返回一张旋转后的图像
134 {
135     //以图像的中心为原点求出原图中的四个角的坐标
136     float SrcX1, SrcY1, SrcX2, SrcY2, SrcX3, SrcY3, SrcX4, SrcY4;
137     //新图中四个角的坐标
138     float DstX1, DstY1, DstX2, DstY2, DstX3, DstY3, DstX4, DstY4;
139     //将角度转换位弧度
140     float alpha = Angle*CV_PI / 180;
141     //原图的宽高
142     int Wold = srcImage.cols;
143     int Hold = srcImage.rows;
144 
145     //假设原图的原点在原图的中心主要是为了求出新图的宽高
146     //原图的四个角的坐标
147     SrcX1 = (float)((-0.5)*Wold);
148     SrcY1 = (float)((0.5)*Hold);
149     SrcX2 = (float)((0.5)*Wold);
150     SrcY2 = (float)((0.5)*Hold);
151     SrcX3 = (float)((-0.5)*Wold);
152     SrcY3 = (float)((-0.5)*Hold);
153     SrcX4 = (float)((0.5)*Wold);
154     SrcY4 = (float)((-0.5)*Hold);
155     //求出cosa 和sina
156     float cosa = cos(alpha);
157     float sina = sin(alpha);
158 
159     //求出新图的四个角的坐标
160     DstX1 = cosa*SrcX1 + sina*SrcY1;
161     DstY1 = -sina*SrcX1 + cosa*SrcY1;
162     DstX2 = cosa*SrcX2 + sina*SrcY2;
163     DstY2 = -sina*SrcX2 + cosa*SrcY2;
164     DstX3 = cosa*SrcX3 + sina*SrcY3;
165     DstY3 = -sina*SrcX3 + cosa*SrcY3;
166     DstX4 = cosa*SrcX4 + sina*SrcY4;
167     DstY4 = -sina*SrcX4 + cosa*SrcY4;
168 
169     //计算新图的宽和高
170     int Wnew = cvRound(max(abs(DstX4 - DstX1), abs(DstX3 - DstX2)));
171     int Hnew = cvRound(max(abs(DstY4 - DstY1), abs(DstY3 - DstY2)));
172 
173     //计算矩阵中的两个常数
174     float num1 = (float)(-0.5*Wnew*cosa - 0.5*Hnew*sina + 0.5*Wold);
175     float num2 = (float)(0.5*Wnew*sina - 0.5*Hnew*cosa + 0.5*Hold);
176     //创建一张新的大小的图
177     Mat resultImage(Hnew, Wnew, srcImage.type());
178     for (int i = 0; i < Hnew; i++) //rows
179     {
180         for (int j = 0; j < Wnew; j++)//cols
181         {
182             //求出新图中的像素在原图的位置
183             int x = cvRound(i*cosa + j*sina + num1);
184             int y = cvRound(-sina*i + j*cosa + num2);
185             if ((x >= 0) && (x < Wold) && (y >= 0) && (y < Hold))//在原图中的范围
186             {
187                 resultImage.at<Vec3b>(i, j) = srcImage.at<Vec3b>(x, y);
188             }
189         }
190     }
191     return resultImage;
192 }
193 int main()
194 {
195 
196     Mat srcImage = imread("D:\倾斜文本.jpg");
197     if (!srcImage.data)
198     {
199         printf("could not load image...
");
200         return -1;
201     }
202     //Point center(srcImage.cols / 2, srcImage.rows / 2);
203     //srcImage = getRotationMatrix2D(center, 27, 1.0);
204     imshow("srcImage", srcImage);
205     //输出傅里叶变换之后的图形
206     Mat DFTImage = DFT(srcImage);
207     imshow("DFT", DFTImage);
208     //求出傅里叶变换里面的倾斜角
209     float theta = AngleDetection(DFTImage);
210     Mat retultImage = RotIamge(srcImage, theta);
211     imshow("res", retultImage);
212     waitKey(0);
213     return 0;
214 }
View Code

参考:

https://blog.csdn.net/linqianbi/article/details/78863839

https://www.cnblogs.com/skyfsm/p/6902524.html

https://blog.csdn.net/liumoude6/article/details/77688798

http://lib.csdn.net/article/opencv/24201 

https://blog.csdn.net/longwinyang/article/details/52789260

https://blog.csdn.net/liyuanbhu/article/details/50099767

http://lib.csdn.net/article/opencv/28857 

https://blog.csdn.net/spw_1201/article/details/53608805

原文地址:https://www.cnblogs.com/thebreakofdawn/p/9502715.html