opencv(20)---轮廓查找与绘制

轮廓

基本概念

轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度,提取轮廓就是提取这些具有相同颜色或者灰度的曲线,或者说是连通域,轮廓在形状分析和物体的检测和识别中非常有用。

注意事项

①为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测
②查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中(clone(), copyTo())
③在OpenCV 中,查找轮廓就像在黑色背景中找白色物体。你应该记住, 要找的物体应该是白色而背景应该是黑色。

常用函数

findContours()—–查找轮廓
drawContours()—–绘制轮廓

实例

这里写图片描述

查找轮廓—findContours()

函数原型

CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                              OutputArray hierarchy, int mode,
                              int method, Point offset = Point());

/** @overload */
CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                              int mode, int method, Point offset = Point());
  • image: 输入图像, Mat类型8位单通道图像(一般为二值图)
  • contours: 检测到的轮廓, 每个轮廓存储为一个点向量, 即Point类型的vector表示
  • hierarchy: 可选的输出向量, 包含图像的拓扑信息。其作为轮廓数量的表示, 包含了许多元素, 每个轮廓contours[i]对应4个
    hierarchy元素hierarchy[i][0]~hierarchy[i][3], 分别表示后一轮廓、前一轮廓、父轮廓、内嵌轮廓的索引编号, 如果没有对应项, 设置为负数
  • mode: 轮廓检索模式, 取值如下:
    CV_RETR_EXTERNAL=0—–表示只检测最外层轮廓
    CV_RETR_LIST=1——提取所有轮廓并放置在list中, 轮廓不建立等级关系
    CV_RETR_CCOMP=2——提取所有轮廓并组织为双层结构
    CV_RETR_TREE=3——提取所有轮廓并重新建立网状轮廓结构
    这里写图片描述

  • method: 轮廓的近似方法, 取值见图2

    这里写图片描述

  • offset: 每个轮廓的可选偏移量, 默认值Point()

绘制轮廓—drawContours()

这里写图片描述

函数原型

CV_EXPORTS_W void 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: 目标图像, Mat类型对象即可
  • contours: 所有的输入轮廓, 每个轮廓存储为一个点向量
  • contourIdx: 轮廓绘制指示变量(索引), 若为负值, 则表示绘制所有轮廓
  • color: 绘制轮廓的颜色
  • thickness: 轮廓线条的粗细, 默认值1, 如果为负值, 则绘制轮廓内部, 可选宏 CV_FILLED
  • lineType: 线条类型, 默认值8
  • hierarcy: 可选的层次结构信息, 默认值noArray()
  • maxLevel: 表示用于绘制轮廓的最大等级, 默认值INT_MAX
  • offset: 可选的轮廓偏移参数, 默认值Point()

轮廓查找与轮廓绘制代码

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    Mat srcImg = imread("D:\\1\\01.png");
    Mat tempImg = srcImg.clone();//进行备份
    Mat draw(srcImg.rows, srcImg.cols, CV_8UC3);
    cvtColor(srcImg, srcImg, CV_BGR2GRAY); //转为灰度图
    threshold(srcImg, srcImg, 50, 255, CV_THRESH_BINARY);//二值化
    imshow("srcImg", srcImg);  //轮廓查找前

    vector<vector<Point>> contours;//两层结构,第一层表示轮廓数,第二层表示轮廓中的点
    vector<Vec4i> hierarchy;

    //findContours(srcImg, contours, hierarchy,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE ); //查找轮廓
    //findContours(srcImg, contours, hierarchy,RETR_LIST, CHAIN_APPROX_SIMPLE ); //查找轮廓
    findContours(srcImg, contours, hierarchy,CV_RETR_CCOMP, CHAIN_APPROX_SIMPLE ); //查找轮廓
    //findContours(srcImg, contours, hierarchy,RETR_TREE, CHAIN_APPROX_NONE ); //查找轮廓
    imshow("cont", srcImg);  //轮廓查找后
    drawContours(tempImg, contours, -1, Scalar(0, 255, 0), 2, 8);  //绘制轮廓
    cout<<"num="<<contours.size()<<endl; //输出轮廓个数
    imshow("contours", tempImg);

    waitKey(0);
}

MainWindow::~MainWindow()
{
}

发现墙面的裂缝

Mat Img=img.clone();
Mat gray;
Mat element0=getStructuringElement(MORPH_RECT,Size(5,5));
Mat element1=getStructuringElement(MORPH_RECT,Size(7,7));
cvtColor(Img,gray,COLOR_RGB2GRAY);
GaussianBlur(gray,gray,Size(255,255),0,0);
adaptiveThreshold(gray,gray,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY_INV,15,3);//自适应滤波
erode(gray,gray,element0);
dialate(gray,gray,element1);

vector<vector<Point>> contours;
vector<vec4i> hierarchy;
findContours(gray,contours,CV_PETE_TREE,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
drawContours(img,contours,-1,Scalar(0,0,255),3,8,hierarchy);
if(!(img.empty())){
 resize(img,img,Size(rect.width(),rect.Height()));
 imshow("PIC",img);
}

访问每一个轮廓以及轮廓上的所有点

访问每一个轮廓

这里写图片描述

访问每一个像素

这里写图片描述

代码一—绘制轮廓

代码1

drawContours(tempImg, contours, -1, Scalar(0, 255, 0), 2, 8); //绘制轮廓

代码2

for(int i=0; i<contours.size(); i++)
{
  drawContours(tempImg, contours, i, Scalar(0, 255, 0), 2, 8); //绘制轮廓

代码1和代码2实现的功能相同

代码二

for(int i=0; i<contours.size(); i++)
{
for(int j=0; j<contours[i].size(); j++)
{
    circle(tempImg, Point(contours[i][j].x, contours[i][j].y), 3, Scalar(0, 255, 0), 2, 8); //画出每个轮廓的每个点
    imshow("contours", tempImg);
}

代码3

for(int i=0; i<contours.size(); i++)
{
   //drawContours(tempImg, contours, i, Scalar(0, 255, 0), 2, 8); //绘制轮廓
   for(int j=0; j<contours[i].size(); j++)
   {

       line(tempImg, Point(3,3), Point(contours[i][j].x, contours[i][j].y), Scalar(0, 0, 255), 1, 8);
       cout<<"("<<contours[i][j].x<<","<<contours[i][j].y<<")"<<endl;
       waitKey(100);
       imshow("contours", tempImg);
   }
}

查找轮廓参数说明

这里写图片描述

这里写图片描述

简单孔洞填充

findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //查找轮廓
drawContours(tempImg, contours, -1, Scalar(0, 255, 0), -1, 8); //绘制轮廓

简单连通域标记

findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //查找轮廓
cout<<"num="<<contours.size()<<endl; //输出轮廓(连通域)个数
for(int i=0; i<contours.size(); i++)
{
    drawContours(tempImg, contours, i, Scalar(rand()%255, rand()%255, rand()%255), -1, 8); //绘制轮廓
}

imshow("contours", tempImg);

总体代码

#include "mainwindow.h"
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    Mat srcImg = imread("D:\\1\\33.png");
    imshow("src", srcImg);
    //Mat tempImg(srcImg.rows, srcImg.cols, CV_8UC3, Scalar(255, 255, 255));
    Mat tempImg = srcImg.clone();  //原图备份
    cvtColor(srcImg, srcImg, CV_BGR2GRAY); //转为灰度图
    threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
    imshow("threshold", srcImg);
    vector<vector<Point>> contours;  //轮廓定义
    vector<Vec4i> hierarcy;

    findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_LINK_RUNS); //查找轮廓
    //drawContours(tempImg, contours, -1, Scalar(0, 255, 0), 2, 8); //绘制轮廓
    for(int i=0; i<contours.size(); i++)
    {
        //drawContours(tempImg, contours, i, Scalar(0, 255, 0), 2, 8); //绘制轮廓
        for(int j=0; j<contours[i].size(); j++)
        {
            circle(tempImg, Point(contours[i][j].x, contours[i][j].y), 3, Scalar(0, 255, 0), 2, 8); //画出每个轮廓的每个点
            //line(tempImg, Point(3,3), Point(contours[i][j].x, contours[i][j].y), Scalar(0, 0, 255), 1, 8);
            //cout<<"("<<contours[i][j].x<<","<<contours[i][j].y<<")"<<endl;
            //waitKey(100);
            imshow("contours", tempImg);
        }
    }

    //孔洞填充
    findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //查找轮廓
    drawContours(tempImg, contours, -1, Scalar(0, 255, 0), -1, 8); //绘制轮廓

    //标记连通域
    findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //查找轮廓
    cout<<"num="<<contours.size()<<endl; //输出轮廓(连通域)个数
    for(int i=0; i<contours.size(); i++)
    {
        drawContours(tempImg, contours, i, Scalar(rand()%255, rand()%255, rand()%255), -1, 8); //绘制轮廓
    }

    imshow("contours", tempImg);
    waitKey(0);
}

MainWindow::~MainWindow()
{

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值