Opencv2 computer vision application programming cookbook<六>

来源:互联网 发布:淘宝网商银行贷款 编辑:程序博客网 时间:2024/05/18 19:18

第七章介绍提取直线,轮廓及连通区域

包括canny算子检测轮廓,霍夫变换检测直线,直线拟合,提取连通区域及连通区域的形状描述符.

#include "stdafx.h"
#include<iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;


#define PI 3.1415926


class LineFinder
{
private:
Mat img;//原图
vector<Vec4i> lines;//向量中包含检测到的直线的端点
double deltaRho;//累加器的分辨率
double deltaTheta;
int minVote;//直线被接受时所需的最小投票数
double minLength;//直线的最小长度
double maxGap;//沿直线方向的最大缺口
public:
//默认的累加器的分辨率为单个像素及1度
//不设置缺口及最小长度的值
LineFinder():deltaRho(1),deltaTheta(PI/180),minVote(10),minLength(0.),maxGap(0.){};
//设置累加器的分辨率
void SetAccResolution(double dRho,double dTheta)
{
deltaRho=dRho;
deltaTheta=dTheta;


}
//设置最小投票数
void SetMinVote(int minv)
{
minVote=minv;
}
//设置缺口及最小长度
void SetLineLengthAndGap(double length,double gap)
{
minLength=length;
maxGap=gap;
}
//使用概率霍夫变换
vector<Vec4i> FindLines(Mat & binary)
{
lines.clear ();
HoughLinesP(binary,lines,deltaRho,deltaTheta,minVote,minLength,maxGap);
return lines;
}
//绘制检测到的直线
void DrawDetectedLines(Mat & image,Scalar color=Scalar(255,255,255))
{
vector<Vec4i>::const_iterator it2=lines.begin();
while(it2!=lines.end())
{
Point pt1((*it2)[0],(*it2)[1]);
Point pt2((*it2)[2],(*it2)[3]);
line(image,pt1,pt2,color);
++it2;
}
}
};
int _tmain(int argc, _TCHAR* argv[])
{
//Mat image=imread("test.bmp",0);
//Mat contours;
//Canny(image,contours,125,350);


//Mat contoursInv;
//threshold(contours,contoursInv,128,255,THRESH_BINARY_INV);


//imshow("",contoursInv);
////Hought变换检测直线
//vector<Vec2f> lines;
//HoughLines(contours,//输入为边缘图像
// lines,
// 1,PI/180,//步进尺寸
// 80);//最小投票数


//vector<Vec2f>::const_iterator it=lines.begin ();
//while(it!=lines.end())
//{
// float rho=(*it)[0];//第一个参数为距离rho
// float theta=(*it)[1];//第二个参数为角度theta
// if(theta<PI/4. || theta>3.*PI/4.)
// {//垂直线
// Point pt1(rho/cos(theta),0);//线与第一行的交点
// Point pt2((rho-contours.rows*sin(theta))/cos(theta),contours.rows);//线与最后一行的交点
// line(image,pt1,pt2,Scalar(255),1);
// }
// else
// {//水平线
// Point pt1(0,rho/sin(theta));//线与第一列的交点
// Point pt2(image.cols,(rho-contours.cols*cos(theta))/sin(theta));//线与最后一列的交点
// line(image,pt1,pt2,Scalar(255),1);
// }
// ++it;
//}
//imshow("lena",image);


//检测直线
Mat image=imread("test.bmp",1);
//创建实例
LineFinder finder;
//设置概率参数
finder.SetLineLengthAndGap(100,20);
finder.SetMinVote(80);
Mat contours;
Canny(image,contours,125,255);
//检测并绘制直线
vector<Vec4i> lines=finder.FindLines(contours);
finder.DrawDetectedLines(image);




//直线拟合
int n=0;//选择line 0
//黑色图像
Mat online(contours.size(),CV_8U,Scalar(0));
//白色直线
line(online,
Point(lines[n][0],lines[n][1]),
Point(lines[n][2],lines[n][3]),
Scalar(255),
5);
//轮廓与白线进行AND操作
bitwise_and(contours,online,online);




vector<Point> points;
//遍历像素得到所有点的位置
for(int y=0;y<online.rows;y++)
{
//Y行
uchar * rowPtr=online.ptr<uchar>(y);
for(int x=0;x<online.cols;x++)
{
//X列
//如果位于轮廓上
if(rowPtr[x])
{
points.push_back (Point(x,y));
}
}

}


Vec4f linesVec;
fitLine(Mat(points),linesVec,
CV_DIST_L2,//距离类型
0,//L2距离不使用该参数
0.01,0.01);//精确值


int x0=linesVec[2];
int y0=linesVec[3];
int x1=x0-200*linesVec[0];
int y1=y0-200*linesVec[1];
line(image,Point(x0,y0),Point(x1,y1),Scalar(0,0,255),5);
imshow("lena",image);




//提取二值图像的轮廓
vector<vector<Point>> contours;
findContours(image,
contours,//轮廓的数组
CV_RETR_EXTERNAL,//获取外轮廓
CV_CHAIN_APPROX_NONE);//获取每个轮廓的每个像素


//findContours(image,contours,
// CV_RETR_LIST,//获取外轮廓,包含所有闭合的轮廓,甚至是有洞的轮廓
// CV_CHAIN_APPROX_NONE);


//vector<Vec4i> hierarchy;
//findContours(image,contours,
// hierarchy,//分层表示
// CV_RETR_TREE,//以树关结构获取轮廓
// CV_CHAIN_APPROX_NONE);//获取每个轮廓的每个像素


Mat result(image.size(),CV_8U,Scalar(255));
drawContours(result,contours,
-1,//绘制所有轮廓
Scalar(0),//颜色为黑色
2);//轮廓线的绘制宽度为2




//连通区域的形状描述符
//此处以后 contours为检测出的轮廓数组
//测试包围盒
Rect r0=boundingRect(Mat(contours[0]));
rectangle(image,r0,Scalar(0),2);


//测试最小包围圆
float radius;
Point2f center;
minEnclosingCircle(Mat(contours[1],center,radius);
circle(image,Point(center),static_cast<int>(radius),Scalar(0),2);


//测试多边形近似
vector<Point> poly;
approxPolyDP(Mat(contours[2]),poly,
5,//近似的精确度
true);//这是个闭合形状
//遍历每个片段进行绘制
vector<Point>::const_iterator itp=poly.begin();
while(itp!=(poly.end()-1))
{
line(result,*itp,*(itp+1),Scalar(0),2);
++itp;
}
//首尾用直线相连
line(result,*(poly.begin ()),*(poly.end ()-1),Scalar(20),2);




//测试凸包
vector<Point> hull;
convexHull(Mat(contours[3],hull);


//力矩Moment
//遍历所有轮廓
itp=contours.begin();
while(itp!=contours.end())
{
//计算所有的力矩
Moments mom=moments(Mat(*itp++));
//质心坐标转换为整数
circle(result,Point(mom.m10/mom.m00,mom.m01/mom.m00),
2,Scalar(0),2);//绘制黑点


}




waitKey();
return 0;
}


0 0