OpenCV —— 轮廓

把检测出的边缘像素组装成轮廓  ——  cvFindContours数组

 

OpenCV 使用内存存储器来统一管理各类动态对象的内存。内存存储器在底层被实现为一个有许多相同大小的内存块组成的双向链表网络

内存储器能够经过四个函数访问 : cvCreateMemStorage(建立一个内存存储器,0采用默认大小)    cvReleaseMemStorage   cvClearMemStorage(和一般释放内存的函数区别 —— 只是将释放的内存返还给内存存储器,而并不返还给系统 —— 能够重复使用内存存储器中的内存空间)  cvMemStorageAlloc (从一个内存存储器中申请空间)函数

序列 —— 序列在内存中被实现为一个双端队列    CvSeq测试

建立序列  cvCreateSeq() —— 须要:序列头的大小 sizeof(CvSeq),以及序列要存储的元素的大小ui

删除序列  cvClearSeq —— 清空序列中的全部元素,但不会将再也不使用的内存返回到内存储器中,也不会释放给系统,当从新向序列中添加元素时,能够重复使用里面的内存块编码

直接访问序列中的元素  cvGetSeqElem spa

检测一个元素是否在序列中   cvSeqElemIdx指针

深度复制一个序列,并建立一个彻底独立的序列结构    cvCloneSeq  (是对cvSeqSlice进行简单的包装 ,cvSeqSlice 函数能够为序列中的子序列生成一个新的序列(深度复制),也能够仅仅为子序列建立一个头,和原来序列共用元素空间)code

cvSeqSort 能够对序列进行排序 —— 须要自定义比较函数对象

cvSeqSearch 搜查序列中的元素

cvSeqInvert 将序列进行逆序操做,不改变元素内容,从新组织

cvSeqPartition 根据用户设定的标准,将函数进行拆分

将队列做为栈使用 —— cvSeqPush   cvSeqPushFront  cvSeqPop   cvSeqPopFront  cvSeqPushMulti   cvSeqPopMulti

序列的读取和写入   CvSeqWriter (由cvStartWriteSeq函数初始化,由cvEndWriteSeq关闭写状态)

—— 写状态被打开的时候可用 CV_WRITE_SEQ , 刚写入的元素对用户来讲可能并不能访问,写操做只有在cvEndWriteSeq 函数后,才会真正被写入到序列中(可经过 cvFlushSeqWriter 函数来显式刷新写操做)

序列和数组之间的转换  ——  cvCvtSeqToArray     cvMakeSeqHeaderForArray

 


轮廓对应一系列的点,也就是图像中的一条曲线,OpenCV中用序列来存储轮廓信息,序列中的每个元素是曲线中一点的位置

cvFindContours 从二值图像中寻找轮廓(处理的图像能够是从cvCanny函数获得的有边缘像素的图像,或者是从cvThreshold 及 cvAdaptiveThreshold 获得的图像,这时的边缘是正和负区域之间的边界)

OpenCV 容许获得的轮廓被聚合成一个轮廓树,从而把包含关系编码到树结构中

图像必须是8位单通道图像,而且应该给转换成二值图像 (运行时,这个图像会被直接涂改,记得备份)

CV_RETR_EXTERNAL  只检测出最外的轮廓

CV_RETR_LIST  检测出全部的轮廓并将它们保存在list中

CV_RETR_CCOMP 检测出全部的轮廓并将它们组织成双层结构,顶层边界是全部成分的外界边界,第二层边界是孔的边界

CV_RETR_TREE  检测出全部的轮廓而且从新创建网络的轮廓结构

使用序列表示轮廓

cvStartFindContours —— 每次返回一个轮廓,而不是像cvFindContours那样一次查找全部的轮廓而后统一返回

cvFindNextContour

cvSubstituteContour —— 用于替换scanner指向的轮廓

cvEndFindContour —— 结束轮廓查找,并将scanner设置为结束状态

绘制轮廓 —— cvDrawContours

#include <cv.h>
#include <highgui.h>

IplImage *g_img=NULL;
IplImage *g_gray=NULL;
int g_thresh=100;
CvMemStorage *g_storage=NULL;

void on_trackbar(int)
{
    if (g_storage==NULL)
    {
        g_gray=cvCreateImage(cvGetSize(g_img),8,1);
        g_storage=cvCreateMemStorage(0);
    }else
    {
        cvClearMemStorage(g_storage);
    }

    CvSeq* contours=0;
    cvCvtColor(g_img,g_gray,CV_BGR2GRAY);
    cvThreshold(g_gray,g_gray,g_thresh,255,CV_THRESH_BINARY);
    cvFindContours(g_gray,g_storage,&contours);
    cvZero(g_gray);

    if(contours)
    {
        cvDrawContours(g_gray,contours,cvScalarAll(255),cvScalarAll(255),100);
    }
    cvShowImage("contours",g_gray);


    
}

int main(int argc,char** argv)
{
    g_img=cvLoadImage("wukong.jpg",CV_LOAD_IMAGE_COLOR);
    cvNamedWindow("contours",1);
    cvCreateTrackbar("threshold","contours",&g_thresh,255,on_trackbar);

    cvWaitKey();
    cvDestroyWindow("contours");
    return 0;
}
#include "cv.h"
#include "highgui.h"
#include "stdio.h"

#define CVX_RED CV_RGB(0xff, 0x00, 0x00)
#define CVX_GREEN CV_RGB(0x00, 0xff, 0x00)
#define CVX_BLUE CV_RGB(0x00, 0x00, 0xff)

int main()
{
    IplImage* img_8uc1 = NULL;
    cvNamedWindow("img_contour", CV_WINDOW_AUTOSIZE);
    
    if (img_8uc1 = cvLoadImage("wukong.jpg", 0))        
        //CV_LOAD_IMAGE_GRAYSCALE == 0 加载lena.jpg 灰度图
    {
        IplImage* img_edge = cvCreateImage(cvGetSize(img_8uc1), 8, 1);
        IplImage* img_8uc3 = cvCreateImage(cvGetSize(img_8uc1), 8, 3);
        
        cvThreshold(img_8uc1, img_edge, 128, 255, CV_THRESH_BINARY);
        //对灰度图img_8uc1 像进行阈值操做获得二值图像 img_edge
        
        CvMemStorage* storage = cvCreateMemStorage();
        //建立一个内存储存器 默认为 64K
        
        CvSeq* first_contour = NULL;
        //建立一个动态序列指针,用其指向第一个存储轮廓单元地址
        
        int NC = cvFindContours(    
            //cvFindContours从二值图像中检索轮廓,并返回检测到的轮廓的个数
            img_edge,        
            storage,                //存储轮廓元素的储存容器
            &first_contour,            //指向第一个输出轮廓
            sizeof (CvContour),        
            CV_RETR_LIST            //提取全部轮廓,而且放置在 list 中
            );
        
        printf("Total Contours Detected: %d\n", NC);
        
        cvCvtColor(img_8uc1, img_8uc3, CV_GRAY2BGR);
        //色彩空间转换,将img_8uc1 转换为BGR空间,img_8uc3 为转换后结果
        
        int n = 0;
        //用于下面轮廓的记数
        for (CvSeq* c=first_contour; c!=NULL; c = c->h_next)
        {    //从第一个轮廓开始遍历,直到全部轮廓都遍历结束
            cvDrawContours(
                img_8uc3,    //用于绘制轮廓的图像
                c,            //指向目前轮廓所在地址空间
                CVX_RED,    //外层轮廓颜色
                CVX_BLUE,    //内层轮廓颜色
                0,            //等级为0,绘制单独的轮廓
                1,            //轮廓线条粗细
                8            //线段类型为(8邻接)链接线
                );
            
            printf("Contour #%d\n", n);
            //输出第 n 个轮廓
            
            cvShowImage("img_contour", img_8uc3);
            //显示目前已绘制的轮廓图像
            
            printf("%d elements:\n", c->total);
            //输出构成目前轮廓点的个数
            
            for (int i=0; i<c->total; i++)
            {
                CvPoint* p = CV_GET_SEQ_ELEM(CvPoint, c, i);
                //查找轮廓序列中索引所指定的点,并返回指向该点的指针
                printf("  (%d, %d)\n", p->x, p->y);
                //输出该点坐标
            }
            
            if (cvWaitKey() == 27)        
                //按下ESC 键退出循环
                break;
            n++;
        }
        printf("Finished all contours. Hit ESC to finish\n");
        
        while (cvWaitKey() != 27);
        
        cvReleaseImage(&img_edge);
        cvReleaseImage(&img_8uc3);
    }
    cvDestroyWindow("img_contour");
    cvReleaseImage(&img_8uc1);
    return 0;
}

 


深刻分析轮廓

多边形逼近 

cvApproxPoly 处理一个轮廓序列,函数的返回值对应第一个轮廓 (由于cvApproxPoly在返回结果的时候须要建立新的对象,所以须要指定一个内存储器以及头结构大小)

特性归纳

长度  cvContourPerimeter 做用于一个轮廓并返回其长度

面积  cvContourArea  计算轮廓面积

边界框

cvBoundingRect —— 返回一个包围轮廓的CvRect

cvMinAreaRect2 —— 返回一个包围轮廓最小的长方形,这个长方形极可能是倾斜的

cvMinEnclosingCircle —— 简单计算彻底包围已有轮廓的最小圆

cvFitEllipse2 —— 使用拟合函数返回一个与轮廓最相近似的椭圆

几何

cvMaxRect —— 根据输入的2个矩形计算,它们的最小外包矩形

cvBoxPoints —— 计算CvBox2D 结构表示矩形的4个顶点

cvPointSeqFromMat —— 从mat中初始化序列

cvPointPolygonTest —— 测试一个点是否在多边形的内部

轮廓的匹配

矩 —— 经过对轮廓上全部点进行积分运算而获得的一个粗略特征

cvContoursMoments —— CvMoments 结构体来保存计算的结果

Hu矩 —— 从中心矩中计算而来(为了可以获取表明图像某个特征的矩函数,这些矩函数对某些变化(缩放,旋转和镜像)具备不变性)

使用Hu矩进行匹配 —— cvMatchShapes

等级匹配

使用轮廓树进行匹配 —— 此处轮廓树是用来描述一个特定形状内各部分的等级关系

cvCreateContourTree

cvContourFromContourTree

cvMatchContourTrees

 

轮廓的凸包和凸缺陷

成对几何直方图 PGH —— 彷佛是为了得到旋转不变性

相关文章
相关标签/搜索