opencv中findContours 和drawContours画图函数

来源:互联网 发布:步态分析数据 编辑:程序博客网 时间:2024/05/18 01:29

由于小博出来游玩,最近还几天没有发帖了,没事在这看看opencv3.1版本的samples,在运行contours时,发现这个小例子还挺有趣的,不多说,我先贴出图,待会儿再细细讲解,各位请自行玩耍
这里写图片描述这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
首先我么导入库文件

#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include <math.h>#include <iostream>

使用opencv命名空间

using namespace cv;using namespace std;

几行解释,让读者更好的了解你的目的,演示什么样的事例(opencv自带):

static void help(){    cout        << "\nThis program illustrates the use of findContours and drawContours\n"        << "The original image is put up along with the image of drawn contours\n"        << "Usage:\n"        << "./contours2\n"        << "\nA trackbar is put up which controls the contour level from -3 to 3\n"        << endl;}

接下来我们分别定义了这个鬼脸的个数(不知道怎么称呼这个图,叫鬼脸吧),调节滚轮,createTrackbar

窗口中快速创建一个滑动控件,用于手动调节阈值,具有非常直观的效果。

函数原型:
int createTrackbar(const string& trackbarname, const string& winname,
int* value, int count,
TrackbarCallback onChange = 0,
void* userdata = 0);

参数说明:

trackbarname:滑动空间的名称;

winname:滑动空间用于依附的图像窗口的名称;

value:初始化阈值;

count:滑动控件的刻度范围;

TrackbarCallback是回调函数。存储轮廓的点集向量以及hierarchy;我们可以先了解一下findContours这个函数才能往后继续学习,findContours函数,这个函数的原型为:

void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierar-
chy, int mode, int method, Point offset=Point())

参数说明

输入图像image必须为一个2值单通道图像(一般用这个函数的时候是对二值化图像操作的)

contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示(这也就是为啥定义一个courtours了)

hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。

mode表示轮廓的检索模式

CV_RETR_EXTERNAL表示只检测外轮廓CV_RETR_LIST检测的轮廓不建立等级关系CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demo

method为轮廓的近似办法

CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。

findContours后会对输入的2值图像改变,所以如果不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似
contourArea函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选
findContours经常与drawContours配合使用

static void on_trackbar(int, void*){    Mat cnt_img = Mat::zeros(w, w, CV_8UC3);    int _levels = levels - 3;    drawContours(cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128, 255, 255),        3, LINE_AA, hierarchy, std::abs(_levels));    imshow("contours", cnt_img);}

ellipse()画椭圆弧函数
功能: 函数ellipse()使用当前绘图色画一椭圆弧。
用法: 该函数调用方式为void ellipse(int x,int y,int startangle,int endangle,
int xradius,int yradius);
说明: 参数x,y为椭圆中心坐标,startangle和endangle为给定的起始角和终止角,xradius与yradius为椭圆的x轴半径与y轴半径,如果startangle为0 ,endangle等于360度,那么画出的是个完整的椭圆。ellipse()函数不同于arc()和circle()函数,屏显纵横比不能自动调节。若需要的是成比例的半径而不是特定的像素距离,则y轴距离必须调节为yradius*aspectratio(y轴半径乘以纵横比)。
此函数对应的头文件为graphics.h
返回值: 无
例: 在屏幕上画一个鸡蛋形的椭圆。

#include<graphics.h>void main(){    int driver,mode;    driver=DETECT;    mode=0;    initgraph(&driver,&mode,"");    ellipse(200,100,0,360,80,40);    getch();    restorecrtmode();}

接下来我们上程序吧

int main(int argc, char** argv){    cv::CommandLineParser parser(argc, argv, "{help h||}");    if (parser.has("help"))    {        help();        return 0;    }    Mat img = Mat::zeros(w, w, CV_8UC1);   //(定义一个500*500的图像)    //我们先画一个原图吧,六个鬼脸    for (int i = 0; i < 6; i++)    {        int dx = (i % 2) * 250 - 30;        int dy = (i / 2) * 150;        const Scalar white = Scalar(255);        const Scalar black = Scalar(0);//  int cvRound (double value) opencv里的一个函数,对一个double型的数进行四舍五入,并返回一个整型数!        if (i == 0)        {            for (int j = 0; j <= 10; j++)            {                double angle = (j + 5)*CV_PI / 21;                line(img, Point(cvRound(dx + 100 + j * 10 - 80 * cos(angle)),                    cvRound(dy + 100 - 90 * sin(angle))),                    Point(cvRound(dx + 100 + j * 10 - 30 * cos(angle)),                        cvRound(dy + 100 - 30 * sin(angle))), white, 1, 8, 0);            }        }        ellipse(img, Point(dx + 150, dy + 100), Size(100, 70), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 115, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 185, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 115, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 185, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 115, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 185, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 150, dy + 100), Size(10, 5), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 150, dy + 150), Size(40, 10), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 27, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 273, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0);    }    //show the faces    namedWindow("image", 1);    imshow("image", img);    //提取轮廓    vector<vector<Point> > contours0;    findContours(img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);    contours.resize(contours0.size());    for (size_t k = 0; k < contours0.size(); k++)        approxPolyDP(Mat(contours0[k]), contours[k], 3, true);/*opencv中利用函数approxPolyDP来对指定的点集进行逼近,其逼近的精度是可设置的,void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed);InputArray curve:输入的点集OutputArray approxCurve:输出的点集,当前点集是能最小包容指定点集的。draw出来即是一个多边形;double epsilon:指定的精度,也即是原始曲线与近似曲线之间的最大距离。bool closed:若为true,则说明近似曲线是闭合的,它的首位都是相连,反之,若为false,则断开。*/    namedWindow("contours", 1);    createTrackbar("levels+3", "contours", &levels, 7, on_trackbar);    on_trackbar(0, 0);    waitKey();    return 0;}

接下来我们把所有代码放上来吧,大家自行copy吧:

#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include <math.h>#include <iostream>using namespace cv;using namespace std;static void help(){    cout        << "\nThis program illustrates the use of findContours and drawContours\n"        << "The original image is put up along with the image of drawn contours\n"        << "Usage:\n"        << "./contours2\n"        << "\nA trackbar is put up which controls the contour level from -3 to 3\n"        << endl;}const int w = 500;int levels = 3;vector<vector<Point> > contours;vector<Vec4i> hierarchy;static void on_trackbar(int, void*){    Mat cnt_img = Mat::zeros(w, w, CV_8UC3);    int _levels = levels - 3;    drawContours(cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128, 255, 255),        3, LINE_AA, hierarchy, std::abs(_levels));    imshow("contours", cnt_img);}int main(int argc, char** argv){    cv::CommandLineParser parser(argc, argv, "{help h||}");    if (parser.has("help"))    {        help();        return 0;    }    Mat img = Mat::zeros(w, w, CV_8UC1);    //Draw 6 faces    for (int i = 0; i < 6; i++)    {        int dx = (i % 2) * 250 - 30;        int dy = (i / 2) * 150;        const Scalar white = Scalar(255);        const Scalar black = Scalar(0);        if (i == 0)        {            for (int j = 0; j <= 10; j++)            {                double angle = (j + 5)*CV_PI / 21;                line(img, Point(cvRound(dx + 100 + j * 10 - 80 * cos(angle)),                    cvRound(dy + 100 - 90 * sin(angle))),                    Point(cvRound(dx + 100 + j * 10 - 30 * cos(angle)),                        cvRound(dy + 100 - 30 * sin(angle))), white, 1, 8, 0);            }        }        ellipse(img, Point(dx + 150, dy + 100), Size(100, 70), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 115, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 185, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 115, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 185, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 115, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 185, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 150, dy + 100), Size(10, 5), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 150, dy + 150), Size(40, 10), 0, 0, 360, black, -1, 8, 0);        ellipse(img, Point(dx + 27, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0);        ellipse(img, Point(dx + 273, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0);    }    //show the faces    namedWindow("image", 1);    imshow("image", img);    //Extract the contours so that    vector<vector<Point> > contours0;    findContours(img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);    contours.resize(contours0.size());    for (size_t k = 0; k < contours0.size(); k++)        approxPolyDP(Mat(contours0[k]), contours[k], 3, true);    namedWindow("contours", 1);    createTrackbar("levels+3", "contours", &levels, 7, on_trackbar);    on_trackbar(0, 0);    waitKey();    return 0;}