图像轮廓生成Freeman码

来源:互联网 发布:鹿晗同性倾向 知乎 编辑:程序博客网 时间:2024/06/07 02:32

图像轮廓生成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;    endend 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}

    调用上述函数代码:

    Freemans(dstimage,FMSS);

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

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

  4. 总结

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