OpenCV提供了CvGraph相關函數,藉助這些函數可以實現圖演算法。下面介紹OpenCV中CvGraph相關函數,並基於這些函數完成映像的寬度優先遍曆演算法,最後附上CvGraph相關的所有函數的用法介紹。
CvGraph、CvGraphVtx、CvGraphEdge結構
結構如下(源碼中宏以作處理):
typedef struct CvGraphVtx{ int flags; //圖演算法中一些標記位,比如深度遍曆、寬度遍曆中對已訪問節點的標記 struct CvGraphEdge* first; //該點輻射的所有邊中的第一條邊}CvGraphVtx;typedef struct CvGraphEdge{ int flags; //圖演算法中一些標記位 float weight; //邊的權重 struct CvGraphEdge* next[2];//該邊起始點串連的下一條邊[0],該邊終止點串連的下一條邊[1] struct CvGraphVtx* vtx[2];//該邊的起始節點和終止節點}CvGraphEdge;typedef struct CvGraph{ CV_SET_FIELDS() /* set of vertices */ \ CvSet* edges; /* set of edges */}CvGraph;
圖的寬度遍曆
主要資料結構介紹完畢,下面程式使用這些資料結構完成圖的寬度遍曆。OpenCV中提供了了CvGraphScanner完成映像的遍曆,但是演算法確實很難用,有興趣的可以讀一下cvNextGraphItem函數。程式基於:
#include "cv.h"#include "highgui.h"#include "cxcore.h"#include "iostream"#include "math.h"#include "time.h"#include <set>#include <queue>using namespace std;#define PI 3.1415926clock_t start,finish;#define VtxNum 6#define EdgeNum 9int main(int argc, char* argv[]){CvGraph *graph;CvMemStorage * storage;int i;storage = cvCreateMemStorage(0);graph=cvCreateGraph(CV_SEQ_KIND_GRAPH,sizeof(CvGraph),sizeof(CvGraphVtx),sizeof(CvGraphEdge),storage);CvGraphEdge *Edges = new CvGraphEdge[EdgeNum];int *VId = new int[VtxNum];//記錄插入節點的索引for (i=0;i<VtxNum;i++){VId[i]=0;}int Flags[VtxNum]={0,1,2,3,4,5};int Weights[EdgeNum]={15,25,19,12,18,35,5,15,45};for (i=0;i<VtxNum;i++){VId[i]=cvGraphAddVtx(graph);}int edge_start[EdgeNum]={VId[0],VId[0],VId[0],VId[0],VId[1],VId[2],VId[3],VId[3],VId[4]};int edge_end[EdgeNum] ={VId[1],VId[2],VId[3],VId[4],VId[2],VId[3],VId[4],VId[5],VId[5]}; for (i=0;i<EdgeNum;i++){Edges[i].weight = Weights[i];cvGraphAddEdge(graph,edge_start[i],edge_end[i],&Edges[i],&Edges_addr[i]);//根據索引插入邊}//圖構建完畢。//開始進行寬度遍曆queue<CvGraphVtx *> VtxQueue;CvGraphVtx *CurVtxOri;CvGraphVtx *CurVtxDst;CvGraphEdge *CurEdge;CurVtxOri=cvGetGraphVtx(graph,VId[0]);CurVtxOri->flags|=CV_GRAPH_ITEM_VISITED_FLAG;VtxQueue.push(cvGetGraphVtx(graph,VId[0]));while (!VtxQueue.empty()){CurVtxOri=VtxQueue.front();VtxQueue.pop();CurEdge=CurVtxOri->first;cout<<cvGraphVtxIdx(graph,CurVtxOri)<<" : " ;while (CurEdge)//如果是有邊的{if (!CV_IS_GRAPH_EDGE_VISITED(CurEdge)){CurEdge->flags|=CV_GRAPH_ITEM_VISITED_FLAG;CurVtxDst=CurEdge->vtx[CurVtxOri==CurEdge->vtx[0]];//找到另一個點if (!CV_IS_GRAPH_VERTEX_VISITED(CurVtxDst)){VtxQueue.push(CurVtxDst);CurVtxDst->flags|=CV_GRAPH_ITEM_VISITED_FLAG;cout<<cvGraphVtxIdx(graph,CurVtxDst)<<" ";}}//好好處理CurEdge變數,區分當前點與邊的關係,參考本部落格第一部分對CvGraphEdge解釋if (CurVtxOri==CurEdge->vtx[0]){CurEdge=CurEdge->next[0];}else{CurEdge=CurEdge->next[1];} }cout<<endl;}return 0;}
CvGraph主要函數說明
函數:int cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* vtx=NULL,CvGraphVtx** inserted_vtx=NULL ); 功能:插入一個頂點到圖中,並返回頂點的索引 參數:graph----要操作的圖 vtx------可選輸入參數,用來初始化新加入的頂點, inserted_vtx----可選的輸出參數。如果不為NULL,則傳回新加入頂點的地址 |
函數:int cvGraphRemoveVtx( CvGraph* graph, int index ); 功能:通過索引刪除一個頂點,連同刪除含有此頂點的邊。如果輸入的頂點不屬於該圖的話,將報告刪除出錯,傳回值為被刪除的邊數,如果頂點不屬於該圖的話,返回-1。 |
函數:int cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ); 功能:刪除一個頂點,連同刪除含有此頂點的邊。如果輸入的頂點不屬於該圖的話,將報告出錯。傳回值為被刪除的邊數,如果頂點不屬於該圖的話,返回-1. |
函數:CvGraphVtx *cvGetGraphVtx(CvGraph*graph,int vtx_idx); 功能:返回索引值是vtx_idx的頂點的指標,如果不存在則返回NULL。 |
函數:int cvGraphVtxIdx(CvGraph * graph,CvGraphVtx *vtx); 功能:返回與vtx相對應的頂點的索引值 |
函數:int cvGraphAddEdge(CvGraph *graph,int start_idx,int end_idx,const CvGraphEdge *edge=NULL,CvGraphEdge **insert_edge=NULL); 參數:start_idx,end_idx 起始頂點和終止頂點的索引值 edge 要插入的邊,其中包含初始化資料 insert_edge 被插入邊的地址 功能:該函數串連兩條特定的頂點。如果成功插入,返回1,如果這條邊已經存在,返回0,如果頂點沒有發現或者起始頂點和終止頂點是同一個點,那麼返回-1. 如果兩個圖的首尾是一樣報錯。 |
函數:int cvGraphAddEdgeByPtr(CvGraph * graph,CvGraphVtx *start_vtx,CvGraphVtx *end_vtx,const CvGraphEdge *edge=NULL,CvGraphEdge**inserted_edge=NULL); 功能:同上 |
函數:void cvGraphRemoveEdge(CvGraph *graph,int start_idx,int end_idx); 功能:刪除串連兩特定頂點的邊,若沒有串連,那麼函數什麼都不做 |
函數:void cvGraphRemoveEdgeByPtr(CvGraph *graph,CvGraphVtx *start_vtx,CvGraphVex *end_vtx); 功能:同上 |
函數:CvGraphEdge* cvFindGraphEdge(CvGraph*graph,int start_idx,int end_idx); 功能:尋找與兩特定頂點相對應的邊,並返回指向該邊的指標。 |
函數:CvGraphEdge *cvFindGraphEdgeByPtr(CvGraph*graph,const CvGraphVtx *start_vtx,const CvGraphVtx *end_vtx); 功能:同上 |
函數:int cvGraphEdgeIdx(CvGraph* graph,CvGraphEdge *edge); 功能:函數返回與邊對應的索引值 |
函數:int cvGraghVtxDegree(const CvGraph* graph,int vtx_idx); 功能:統計與頂點相關聯的邊數,包括以該頂點為起始點和以該頂點以終止節點的。 |
宏:CV_NEXT_GRAPH_EDGE(CvGraphEdge* ,CvGraphVtx *); 功能:返回依附於該頂點的下一條邊 |
函數: int cvGraphVtxDegreeByPtr(const CvGraph *graph,const CvGraphVtx *vtx); 功能:同上 |
函數:void cvClearGraph(CvGraph *graph); 功能:刪除該圖所有的頂點和所有的邊,時間複雜度是O(1) |
函數:CvGraph* cvCloneGraph(const CvGraph *graph,CvMemStorate * storage); 參數:storage:容器,存放拷貝 功能:函數cvCloneGraph建立映像的完全拷貝,如果頂點和邊含有指向外部變數的指標,那麼圖和它的拷貝共用這些指標。 |
| |