OpenCV学习:CvGraph相关函数

 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.1415926
clock_t start,finish;

#define VtxNum 6
#define EdgeNum 9
int 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创建图像的完全拷贝,如果顶点和边含有指向外部变量的指针,那么图和它的拷贝共享这些指针。
 

### 回答1: opencv中的mat::zeros函数是用来创建一个指定大小和类型的全零矩阵的函数。它的语法如下: cv::Mat cv::Mat::zeros(int rows, int cols, int type) 其中,rows和cols分别表示矩阵的行数和列数,type表示矩阵的类型,可以是CV_8UC1、CV_8UC3、CV_32FC1等等。函数返回一个指定大小和类型的全零矩阵。 ### 回答2: opencv中的mat::zeros函数是一个用于创建一个指定大小和类型的矩阵的函数。该函数的原型如下: Mat cv::Mat::zeros(int rows, int cols, int type) 其中,rows表示矩阵的行数,cols表示矩阵的列数,type表示矩阵的数据类型,常用的数据类型包括CV_8U、CV_8S、CV_16U、CV_16S、CV_32S、CV_32F、CV_64F等。该函数返回一个新创建的矩阵,初始化所有元素为0。 使用Mat::zeros函数可以快速创建一个指定大小和类型的矩阵,并且初始化为0,而不用手动遍历矩阵并设置每个元素的值。这在一些像处理的操作中非常有用,例如在创建掩膜矩阵时,可以使用该函数创建一个大小和像一样的全零矩阵,然后在需要的位置设置为1或其他值。 下面是一个示例代码,使用mat::zeros函数创建了一张大小为512x512,类型为CV_8UC1的全零像: Mat img = Mat::zeros(512, 512, CV_8UC1); 需要注意的是,mat::zeros函数创建的矩阵所有元素的值都是0,而不是默认值。如果需要创建一个矩阵并且初始化为其它默认值,可以使用其重载函数,例如: Mat img = Mat::zeros(512, 512, CV_8UC3); Mat img2 = Mat::zeros(Size(512, 512), CV_8UC3); Mat img3 = Mat::zeros(img.size(), img.type()); 其中,img2使用了Size类型来指定矩阵的大小,img3则使用现有的矩阵来指定矩阵的大小和类型。 ### 回答3: opencv中的mat::zeros函数是用于创建一个具有指定行数、列数和类型的矩阵,并将所有像素的值设置为0的函数。这个函数可以创建单通道或多通道的矩阵,可以是8位、16位、32位或64位浮点型,也可以是8位、16位或32位整数型。该函数返回一个与所创建矩阵相同类型的空矩阵。 该函数有两种格式,第一种格式是: Mat dst = Mat::zeros(int rows, int cols, int type); 参数说明: rows:矩阵的行数; cols:矩阵的列数; type:矩阵的类型,包括如下几种: CV_8U:8位无符号整数型; CV_8S:8位有符号整数型; CV_16U:16位无符号整数型; CV_16S:16位有符号整数型; CV_32S:32位有符号整数型; CV_32F:32位浮点型; CV_64F:64位浮点型。 第二种格式是: void cv::Mat::zeros(InputArray _src, Scalar value=Scalar::all(0)) 参数说明: _src:矩阵,用于接收零矩阵; value:可选的参数,用于设置矩阵像素的值,默认值为Scalar::all(0),即所有像素设置为0。 总之,mat::zeros函数是一种非常方便的创建空矩阵并初始化像素值的方法。它可以用于像处理、计算机视觉、机器学习等众多领域。在许多opencv应用中,需要先创建一个空矩阵,并将其作为输出参数传递给其他函数。因此,mat::zeros函数可以简化代码,提高开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值