本例程涉及到几个数据结构及方法,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))<threshold1,则在层 i 的象素点 a 和它的相邻层的父亲象素 b 之间的连接被建立起来,
定义好连接部件后,它们被加入到某些簇中。如果p(c(A),c(B))<threshold2,则任何两个分割 A 和 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; i<seq ->total;++i)
{
CvPoint *p = (CvPoint *)cvGetSeqElem(seq,i);
}
2. seq是需要检测的序列,而index顾名思义是元素在序列中的索引,即第几个元素
/*整体思路是先分割图像,形成各部分轮廓,然后连接图像各部分*/
- #include <cv.h>
- #include <stdio.h>
- #include <highgui.h>
- 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 );
- }
/*结果*/