NO IMAGE

影象輪廓生成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
    }

    呼叫上述函式程式碼:

    Freemans(dstimage,FMSS);

    dstimage是用邊緣檢測演算法檢測出的邊緣,FMSS是存放輪廓點及其Freeman碼的容器,包含三個元素,你懂的。

    至此,兩個版本的輪廓生成Freeman碼都寫完了,無論是matlab還是OpenCV,兩個版本的演算法共同的缺點是對於非閉合輪廓會生成兩遍,閉合輪廓是沒問題的。我的另外一篇部落格OpenCV八鄰域輪廓跟蹤演算法同樣的也可以生成Freeman碼,但個人認為首選OpenCV自帶的庫函式還是比較好。

  4. 總結

    在生成Freeman碼過程中,付出很多,查詢很多資料,有時候看見網上一些關於輪廓生成Freeman的帖子蜻蜓點水就來氣,沒有實用的方法生成Freeman碼,所以自己將自己得成果整理出來奉獻出來相互學習交流,不足的地方望批評指正,謝謝大家!