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 —— 彷佛是爲了得到旋轉不變性

相關文章
相關標籤/搜索