2016/10/07 阅读《Practical OpenCV》 char5

本文介绍了一个使用OpenCV实现的轮廓检测程序,通过鼠标点击显示最小包含轮廓。程序首先进行边缘检测并提取轮廓,然后通过近似多边形形成封闭轮廓。用户点击图像时,程序能找出包含点击点的最小轮廓并高亮显示。
摘要由CSDN通过智能技术生成

下面这段代码是书中的源码。这篇博客主要是想要把程序的目的、思路、实现方法和几个关键点整理一下。

#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');
}
  1. 目的
    程序的目的是为了能够找到图片中的所有的轮廓,并且通过鼠标交互,来显示包含鼠标的最小轮廓。
  2. 思路
    首先通过对图像进行边缘检测,利用边缘信息得到轮廓,再通过函数make_contours_closed寻找近似多边形, 形成封闭的轮廓;随后从等级最高的多边形开始,检验鼠标点在轮廓内部或者外部,在内部的则检验更低等级的多边形,在外面的话则检验同等级的其他多边形,一直到确定是包含鼠标点的最小多边形为止,并且显示。
  3. 实现方法
    下面的图片是程序的大致流程:
    上面程序的大致流程
  4. 关键点
    主要是想弄明白流程,另外一个点就是理解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声明的时候需要在后面的两个“>”之间加上空格,否则会被认为是重载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值