第五章 - 图像形态学 - 基于图像金字塔的图像分割(cvPyrSegmentation)

本例程涉及到几个数据结构及方法,CvMemStorage、cvPyrSegmentation()、CvConnectedComp、cvGetSeqElem().

 

CvMemStorage

CvMemStorage
Growing memory storage

typedef struct CvMemStorage
{
struct CvMemBlock* bottom;/* first allocated block */
struct CvMemBlock* top; /* the current memory block - top of the stack */
struct CvMemStorage* parent; /* borrows new blocks from */
int block_size; /* block size */
int free_space; /* free space in the top block (in bytes) */
} CvMemStorage;
内存存储器是一个可用来存储诸如序列,轮廓,图形,子划分等动态增长数据结构的底层结构。它是由一系列以同等大小的内存块构成,呈列表型 ---bottom 域指的是列首,top 域指的是当前指向的块但未必是列尾.在bottom和top之间所有的块(包括bottom, 不包括top)被完全占据了空间;在 top和列尾之间所有的块(包括块尾,不包括top)则是空的;而top块本身则被占据了部分空间 -- free_space 指的是top块剩馀的空字节数。

新分配的内存缓冲区(或显式的通过 cvMemStorageAlloc 函数分配,或隐式的通过 cvSeqPush, cvGraphAddEdge等高级函数分配)总是起始于当前块(即top块)的剩馀那部分,如果剩馀那部分能满足要求(够分配的大小)。分配后,free_space 就减少了新分配的那部分内存大小,外加一些用来保存适当列型的附加大小。当top块的剩馀空间无法满足被分配的块(缓冲区)大小时,top块的下一个存储块被置为当前块(新的top块) -- free_space 被置为先前分配的整个块的大小。

如果已经不存在空的存储块(即:top块已是列尾),则必须再分配一个新的块(或从parent那继承,见 cvCreateChildMemStorage)并将该块加到列尾上去。于是,存储器(memory storage)就如同栈(Stack)那样, bottom指向栈底,(top, free_space)对指向栈顶。栈顶可通过 cvSaveMemStoragePos保存,通过 cvRestoreMemStoragePos 恢复指向, 通过 cvClearStorage 重置。

 

cvPyrSegmentation

PyrSegmentation
用金字塔实现图像分割

void cvPyrSegmentation( IplImage* src, IplImage* dst,
CvMemStorage* storage, CvSeq** comp,
int level, double threshold1, double threshold2 );
src
输入图像.
dst
输出图像.
storage
Storage: 存储连通部件的序列结果
comp
分割部件的输出序列指针 components.
level
建立金字塔的最大层数
threshold1
建立连接的错误阈值
threshold2
分割簇的错误阈值
函数 cvPyrSegmentation 实现了金字塔方法的图像分割。金字塔建立到 level 指定的最大层数。如果 p(c(a),c(b))
定义好连接部件后,它们被加入到某些簇中。如果p(c(A),c(B))
如果输入图像只有一个通道,那么

p(c1,c2)=|c1-c2|.
如果输入图像有单个通道(红、绿、兰),那幺

p(c1,c2)=0,3·(c1r-c2r)+0,59·(c1g-c2g)+0,11·(c1b-c2b) .
每一个簇可以有多个连接部件。图像 src 和 dst 应该是 8-比特、单通道 或 3-通道图像,且大小一样

 

CvConnectedComp

CvConnectedComp
连接部件、连接图像各部分

typedef struct CvConnectedComp
{
double area; /* 连通域的面积 */
float value; /* 分割域的灰度缩放值 */
CvRect rect; /* 分割域的 ROI */
} CvConnectedComp;

cvGetSeqElem

openCV里面的一个函数

作用:直接访问序列中的元素

格式:char * cvGetSeqElem(seq,index)

用法:

1. 首先返回的是char类型的指针,当然也可以利用强制类型转换,转换为序列中实际存储的数据类型

例如:for(int i = 0; itotal;++i)

{

        CvPoint *p = (CvPoint *)cvGetSeqElem(seq,i);

}

2. seq是需要检测的序列,而index顾名思义是元素在序列中的索引,即第几个元素

 

/*整体思路是先分割图像,形成各部分轮廓,然后连接图像各部分*/

 

#include 
#include 
#include 

void f( IplImage* src, IplImage* dst );

int main(int argc, char** argv )
{
	cvNamedWindow( argv[1], 1 );  //create a named window
	IplImage* src = cvLoadImage( argv[1] ); //load the image
	if( !src ) 
	{
		printf( "Couldn't seem to open %s", argv[1] );  //if not exist the image
		return -1;
	}
	IplImage* dst = cvCreateImage( cvGetSize( src ), src->depth, src->nChannels );  //create the image head and allocate the data
	f( src, dst ); //call the function f

	cvShowImage( argv[1], dst );  //show the image in the named window
	while( 1 ) //wait until the user hits the "ESC" key
	{
		if( cvWaitKey( 100 ) == 27 )
			break;
	}

	cvDestroyWindow( argv[1] ); //clean up the window and release the memory
	cvReleaseImage( &src ); //the parameter is a point
	cvReleaseImage( &dst );

	return 0;
}

void f( IplImage* src, IplImage* dst )
{
	CvMemStorage* storage = cvCreateMemStorage( 0 );  //apply the memory storage for the growing image data structure
	CvSeq* comp = NULL;  //growable sequence of the elements
	
	cvPyrSegmentation( src, dst, storage, &comp, 4, 200, 50 );  //image segmentation and store the outline sequence
	int n_comp = comp->total;  //total number of elements

	for( int i = 0; i < n_comp; ++i )
	{
		CvConnectedComp* cc = ( CvConnectedComp* )cvGetSeqElem( comp, i );  //connect the image
		//
	}
	cvReleaseMemStorage( &storage );
}


/*结果*/

 

你可能感兴趣的:(CV/PR/opencv)