图像轮廓生成Freeman码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liumangmao1314/article/details/72636910

图像轮廓生成Freeman码

  1. 摘要

    Freeman码是描述轮廓的另外一种形式,这篇博客我将会用matlab和OpenCV两个版本生成Freeman码。纵观网上很多介绍边缘轮廓的,都提到过Freeman码,但是实现却比较少。

  2. 准备工作

    2.1 matlab版
    matlab自身是不带边界轮廓跟踪生成Freeman码算法函数的。起初我做的时候,网上有介绍matlab轮廓生成Freeman码函数,给个链接matlab生成Freeman码介绍,但是在matlab编辑器上写这个函数时,发现报错”未定义boundaries函数”。其实这个函数是书本《数字图像处理MATLAB版》的库函数,matlab不自带,故需要在matlab中添加库函数,我有资源冈萨雷斯数字图像MATLAB处理库函数,具体添加工作可以百度,也可以问我。
    2.2 OpenCV版
    OpenCV不需要准备工作。

  3. Freeman码的生成
    3.1 matlab版

    用matlab生成Freeman码的代码可以在我给出的那篇博客中复制过来,我把生成Freeman码的代码写进了一个function中,在以前基础上,我将每个轮廓点的和它的链码(即它下一个点在它的那个方向上)存起来以更好的下一步工作,代码如下:

    function contours=freeman(im_edge)% 函数定义
    c=boundaries(im_edge,8);%生成Freeman码
    contours=cell(size(c,1),1);
    index=1;
    %     [L,W]=size(im_edge);%观察轮廓
    %     im_edge(c{1}(:,1)+(c{1}(:,2)-1)*L)=1;
    %     imshow(im_edge);
    while index<=size(c,1)
        if length(c{index})<40
            c(index)=[];
        else
            h=fchcode(c{index,:},8);
            contour=c{index,1}(1:length(h.fcc),:);
             contour=[contour,h.fcc'];%提取Freeman并和轮廓点组合
             contours{index,1}=contour;
            index=index+1;
        end
    end
     contours(index:end,:)=[];
    end

    调用上述函数代码:

    contours=freeman(im_edge);

    contours生成的Freeman就在元胞数组里,可以进行下一步工作了。另外,matlab语言我还不是很熟练,很多用法都是业余水平,望指教!

    3.2 OpenCV版

    OpenCV自带轮廓提取的库函数是findContours(),这是C++接口函数,目前我还没有用findContours()函数生成Freeman码,这里我是使用C语言接口的函数cvFindContours(),但是这并不影响我们使用C++调用OpenCV的库函数。在这里感谢原帖如何取得Freeman链码,帖子上代码是没什么问题的,但是美中不足的是在提取轮廓点坐标时有错误,我自己摸索出解决方法,同样的,我也将提取Freeman码写进一个函数供调用,OpenCV生成Freeman码的代码如下:

    void Freemans(Mat srcimage,vector<vector<FM>>&FMS)
    {
    CvMat _srcimage = srcimage;
    CvMemStorage* storage = cvCreateMemStorage();//采用默认大小,即:0.
    CvSeq* first_contour = NULL;
    int Nc = cvFindContours(&_srcimage,storage,&first_contour,sizeof(CvContour),
                                CV_RETR_CCOMP, 
                                CV_CHAIN_CODE,///*这个是关键参数*/
                                cvPoint(0, 0)
                                );
    
    CvChain* chain = 0;
    vector<CvSeq*>c1;
    CvSeq* h;
    for( CvSeq* c = first_contour; c != NULL;c=c->h_next)
    {
        vector<FM>fms;
        int total=c->total;
    
        if(total<20)
            c=c->h_next;
        else
        {
            CvSeqReader reader;
            cvStartReadSeq( (CvSeq*)c, &reader, 0 );
            CvChainPtReader reader1;
            cvStartReadChainPoints((CvChain*)c, &reader1);
            FM fm;
            for( int i = 0; i < total; i++ )
            {
                char code;
                CV_READ_SEQ_ELEM( code, reader ); //printf(" %d,",code); //得到轮廓的Freeman链码序列
                fm.direction=code;
                CvPoint pt;
                CV_READ_CHAIN_POINT(pt,reader1);
                fm.x=pt.x;
                fm.y=pt.y;
                fms.push_back(fm);
            }
            FMS.push_back(fms);
        }
    }//for
    }

    调用上述函数代码:

    扫描二维码关注公众号,回复: 3338563 查看本文章
    Freemans(dstimage,FMSS);

    dstimage是用边缘检测算法检测出的边缘,FMSS是存放轮廓点及其Freeman码的容器,包含三个元素,你懂的。

    至此,两个版本的轮廓生成Freeman码都写完了,无论是matlab还是OpenCV,两个版本的算法共同的缺点是对于非闭合轮廓会生成两遍,闭合轮廓是没问题的。我的另外一篇博客OpenCV八邻域轮廓跟踪算法同样的也可以生成Freeman码,但个人认为首选OpenCV自带的库函数还是比较好。

  4. 总结

    在生成Freeman码过程中,付出很多,查找很多资料,有时候看见网上一些关于轮廓生成Freeman的帖子蜻蜓点水就来气,没有实用的方法生成Freeman码,所以自己将自己得成果整理出来奉献出来相互学习交流,不足的地方望批评指正,谢谢大家!

猜你喜欢

转载自blog.csdn.net/liumangmao1314/article/details/72636910