⼆值图像分析:⼆值图像轮廓提取
⼆值图像分析:⼆值图像轮廓提取
1.OpenCV中的图像轮廓
⼀个轮廓对应⼀系列的点(cv::Point()),这些点以某种⽅式表⽰图像中的⼀条曲线。在OpenCV中,轮廓通过STL中的vector表⽰,向量中的每⼀个值包含轮廓上下⼀个点的位置信息。
2.轮廓提取相关API总结
2.1 轮廓发现findContours
OpenCV提供findContours()函数来获取⼆值图像的轮廓拓扑信息,其函数原型如下:
void cv::findContours(InputOutputArray image,OutputArrayOfArrays contours,
OutputArray hierarchy,int mode,int method,Point offset =Point())
参数解释:
image:表⽰输⼊图像,它必须是⼆值图像,⼆值图像可以由threshold、adaptiveThreshold、Canny、inRange等⽅法得到。
Contours:⽤来获取轮廓,每个轮廓是⼀系列的点(cv::Point类)集合。
Hierarchy:⽤来保存轮廓的层次信息,因为⼀个轮廓⾥可能包含另⼀个轮廓,每个轮廓有四个相关信息,分别是同层下⼀个、前⼀个、第⼀个⼦节点以及⽗节点。
mode:表⽰轮廓寻时候的拓扑结构返回,常⽤的有2种选择:RETR_EXTERNAL表⽰只返回最外层轮廓,RETR_TREE表⽰返回轮廓树结构。
Method:表⽰轮廓点集合取得是基于什么算法,常见的是基于CHAIN_APPROX_SIMPLE链式编码⽅法。
2.2 轮廓绘制drawContours
对于得到轮廓,可以通过下⾯的API绘制每个轮廓:
void cv::drawContours(InputOutputArray image,InputArrayOfArrays contours,
int contourIdx,const Scalar& color,int thickness =1,
int lineType = LINE_8,InputArray hierarchy =noArray(),
int maxLevel = INT_MAX,Point offset =Point())
image:为绘制到的图像。
contours:为轮廓集合,当中每个元素为⼀个轮廓。
contourIdx:为 绘制contours中序号对应的轮廓,为-1时则表⽰绘制所有轮廓。
color:绘制使⽤的颜⾊。
thickness:为正数的时候表⽰绘制该轮廓,为-1表⽰填充该轮廓。
2.3 轮廓外接矩形获取boundingRect和minAreaRect
对于⼆值图像的每个轮廓,OpenCV提供了API可以求取轮廓的外接矩形,其中求取轮廓外接矩形有两种⽅式:最⼤外接矩形和最⼩外接矩形。
最⼤外接矩形API如下:
Rect cv::boundingRect(InputArray points)
参数解释:
points可以⼀系列点的集合,对轮廓来说就是该轮廓的点集
返回结果是⼀个矩形,包含坐标及长宽等信息。
最⼩外接矩形API如下:
RotatedRect cv::minAreaRect(InputArray point)
参数解释:
points可以⼀系列点的集合,对轮廓来说就是该轮廓的点集
返回结果是⼀个旋转矩形,包含下⾯的信息:矩形中⼼位置cx,cy;矩形的宽⾼h,w;旋转⾓度。
2.4 轮廓⾯积与弧长获取
对于⼆值图像的每个轮廓,可以计算轮廓的弧长与⾯积,然后根据轮廓的⾯积与弧长可以实现对不同⼤⼩对象的过滤,寻到感兴趣的区域。OpenCV提供了对轮廓点集计算⾯积的API,其原理是基于格林公式。
OpenCV对轮廓点集计算⾯积的API函数如下:
double cv::contourArea(InputArray contour,bool oriented=false)
参数解释:
contour:表⽰输⼊的轮廓点集。
oriented:默认是false,返回的⾯积是正数,如果⽅向参数为true表⽰会根据是顺时针或者逆时针⽅向返回正值或者负值⾯积。OpenCV计算轮廓曲线的弧长的API函数如下:
double cv::arcLength(InputArray curve,bool closed )
参数解释:
curve:表⽰输⼊的轮廓点集。
closed:默认表⽰是否闭合区域。
2.代码实践
#include<iostream>
#include<vector>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage =imread("/mnt/hgfs/winshare/images/circles.jpg");
pty())
{
cout<<"load image failed."<<endl;
return-1;
}
imshow("src",srcImage);
Mat dstImage,blurImage,grayImage,binaryImage;
//⼆值化图像
GaussianBlur(srcImage,blurImage,Size(3,3),0,0);
cvtColor(blurImage,grayImage,COLOR_BGR2GRAY);
threshold(grayImage,binaryImage,200,255,THRESH_BINARY_INV);
threshold(grayImage,binaryImage,200,255,THRESH_BINARY_INV);
imshow("binary",binaryImage);
//轮廓提取
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binaryImage,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
Mat dst1=srcImage.clone();
Mat dst2=srcImage.clone();
for(int i=0;i<contours.size();++i)
{
//绘制轮廓
drawContours(dst1,contours,i,Scalar(0,0,255),-1,8);
drawContours(dst2,contours,i,Scalar(0,0,255),1,8);
//最⼤外接矩形
Rect rect =boundingRect(contours[i]);
rectangle(srcImage,rect,Scalar(255,0,0),1,8,0);
//最⼩外接矩形
RotatedRect rrt =minAreaRect(contours[i]);
Point2f pts[4];
rrt.points(pts);
for(int i=0;i<4;++i)
{
line(srcImage,pts[i%4],pts[(i+1)%4],Scalar(0,255,0),2,8,0);
}
//中⼼点绘制
Point2f cpt = ;
circle(srcImage,cpt,2,Scalar(255,0,0),2,8,0);
//获取轮廓⾯积和弧长
cout<<"Area "<<i<<" = "<<contourArea(contours[i])<<",Length "<<i<<" = "<<arcLength(contours[i],true)<<endl; }
imshow("dst",srcImage);
imshow("ticks=-1,contours",dst1);
imshow("ticks=1,contours",dst2);
#endif
waitKey(0);
return0;
}
运⾏结果:
rectangle函数opencv
输⼊图像:
⼆值化图像:
绘制轮廓:
填充绘制轮廓:
最⼤和最⼩外接矩形绘制:
输出轮廓⾯积和弧长:
Area 0 = 25870,Length 0 = 602.156 Area 1 = 13916,Length 1 = 440.96 Area 2 = 1529,Length 2 = 147.196 Area 3 = 5761,Length 3 = 283.764
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论