下面这段代码是书中的源码。这篇博客主要是想要把程序的目的、思路、实现方法和几个关键点整理一下。
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
Mat img_all_contours;
vector<vector<Point> > closed_contours;
vector<Vec4i> hierarchy;
//function to approximate contours by closed contours
vector<vector<Point> > make_contours_closed(vector<vector<Point>> contours)
{
vector<vector<Point> > closed_contours;
closed_contours.resize(contours.size());
for(int i=0;i<contours.size();i++)
{
approxPolyDP(contours[i],closed_contours[i],0.1,true);
}
return closed_contours;
}
//function to return the index of smallest contours in 'closed_contours' surrounding the clicked point
int smallest_contour(Point p,vector<vector<Point>> contours,vector<Vec4i> hierarchy)
{
int idx = 0;
int prev_idx = -1;
while(idx >= 0)
{
vector<Point> c = contours[idx];
/point-polgon test
double d = pointPolygonTest(c,p,false);
/if point is inside the contour,check its children for an even smaller contour
if(d > 0)
{
prev_idx = idx;
idx = hierarchy[idx][2];
}
///else check the next contour on the same level
else
{
idx = hierarchy[idx][0];
}
}
return prev_idx;
}
void on_mouse(int event ,int x,int y,int,void*)
{
if(event != EVENT_LBUTTONDOWN)
{
return;
}
//clicked point
Point p(x,y);
//find index of smallest enclosing contour
int contour_show_idx = smallest_contour(p,closed_contours,hierarchy);
//if no such contours,user clicked outside all contours,hence clear image
if(contour_show_idx < 0)
{
imshow("Contours",img_all_contours);
return;
}
///draw the smallest contour using a thick red line
vector<vector<Point> > contour_show;
contour_show.push_back(closed_contours[contour_show_idx]);
if(!contour_show.empty())
{
Mat img_show = img_all_contours.clone();
drawContours(img_show,contour_show,-1,Scalar(0,0,255),3);
imshow("Contours",img_show);
}
}
void main(void)
{
Mat img = imread("E:\\opencv-logo.png");
img_all_contours = img.clone();
Mat img_b;
cvtColor(img,img_b,CV_RGB2GRAY);
Mat edges;
Canny(img_b,edges,50,100);
extract contours and hierarchy
vector<vector<Point> > contours;主要是要理解这一行是个什么操作机制
findContours(edges,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);
//make contours closed so point-polygon test is valid
closed_contours = make_contours_closed(contours);
draw all contours using green line
drawContours(img_all_contours,closed_contours,-1,Scalar(0,255,0));
imshow("Contours",img_all_contours);
//Mouse callback
setMouseCallback("Contours",on_mouse);
while(char(waitKey(1)) != 'q');
}
- 目的
程序的目的是为了能够找到图片中的所有的轮廓,并且通过鼠标交互,来显示包含鼠标的最小轮廓。 - 思路
首先通过对图像进行边缘检测,利用边缘信息得到轮廓,再通过函数make_contours_closed寻找近似多边形, 形成封闭的轮廓;随后从等级最高的多边形开始,检验鼠标点在轮廓内部或者外部,在内部的则检验更低等级的多边形,在外面的话则检验同等级的其他多边形,一直到确定是包含鼠标点的最小多边形为止,并且显示。 - 实现方法
下面的图片是程序的大致流程:
- 关键点
主要是想弄明白流程,另外一个点就是理解vector
#include<vector>
#include<iostream>
using namespace std;
void main(void)
{
int x;
cin>>x;
while(x<2)
{
cout<<"input must larger than 1!"<<endl;
cin>>x;
}
vector<vector<char> > tri;
int i,j;
vector<char> tmp;
for(i = 0;i <= x+1; i++)
{
tmp.clear();
for(j = 0;j < i;j++)
{
tmp.push_back('*');///注意这个附近的区别
}
tri.push_back(tmp);
}
for(int i = 0;i < x+1; i++)
{
for(int j = 0;j < i;j++)
{
cout<<tri[i][j];
}
cout<<endl;
}
system("pause");
}
但是不能使用下面的方法,这个还在思考为什么,也解释不了书上的代码的意思。(新增加:其实可以解释了:就是最开始声明了vector
#include<vector>
#include<iostream>
using namespace std;
void main(void)
{
int x;
cin>>x;
while(x<2)
{
cout<<"input must larger than 1!"<<endl;
cin>>x;
}
vector<vector<char> > tri;
int i,j;
vector<char> tmp;
for(i = 0;i <= x+1; i++)
{
for(j = 0;j < i;j++)
{
tri[i].push_back('*');///注意这一行和上面的代码的区别
}
}
for(int i = 0;i < x+1; i++)
{
for(int j = 0;j < i;j++)
{
cout<<tri[i][j];
}
cout<<endl;
}
system("pause");
}
还有个讲究,就是二维的或者多为的vector声明的时候需要在后面的两个“>”之间加上空格,否则会被认为是重载。