Although algorithms like the Canny edge detector can be used to find the edge pixels that
separate different segments in an image, they do not tell you anything about those edges as
entities in themselves. The next step is to be able to assemble those edge pixels into
contours. By now you have probably come to expect that there is a convenient function in
OpenCV that will do exactly this for you, and indeed there is: cvFindContours()
. We will start out this chapter with some basics that we will
need in order to use this function. Specifically, we will introduce memory storages, which are how OpenCV functions gain access to memory when they need to
construct new objects dynamically; then we will learn some basics about sequences, which are
the objects used to represent contours generally. With those concepts in hand, we will get
into contour finding in some detail. Thereafter we will move on to the many things we can do
with contours after they've been computed.
OpenCV uses an entity called a memory storage as its method of handling memory allocation for dynamic objects. Memory storages are linked lists of memory blocks that allow for fast allocation and de-allocation of continuous sets of blocks. OpenCV functions that require the ability to allocate memory as part of their normal functionality will require access to a memory storage from which to get the memory they require (typically this includes any function whose output is of variable size).
Memory storages are handled with the following four routines:
CvMemStorage* cvCreateMemStorage( int block_size = 0 ); void cvReleaseMemStorage( CvMemStorage** storage ); void cvClearMemStorage( CvMemStorage* storage ); void* cvMemStorageAlloc( CvMemStorage* storage, size_t size );
To create a memory storage, the function cvCreateMemStorage()
is
used. This function takes as an argument a block size, which gives the size of memory blocks
inside the store. If this argument is set to 0 then the default block size (64kB) will be
used. The function returns a pointer to a new memory store.
The cvReleaseMemStorage()
function takes a pointer to
a valid memory storage and then de-allocates the storage. This is essentially equivalent to
the OpenCV de-allocations of images, matrices, and other structures.
You can empty a memory storage by calling cvClearMemStorage()
, which also takes a pointer to a valid storage. You must be
aware of an important feature of this function: other than cvReleaseMemStorage(), it is the
only way to reuse the memory allocated to a memory storage. This might not seem like much,
but there will be other routines that delete objects inside of memory storages (we will
introduce one of these momentarily) but do not return the memory they
were using. In short, only cvClearMemStorage()
(and, of
course, cvReleaseMemStorage()
) recycle the storage
memory.[102] Deletion of any dynamic structure (CvSeq,
CvSet
, etc.) never returns any memory back to storage (although the structures
are able to reuse some memory once taken from the storage for their own data).
You can also allocate your own continuous blocks from a memory storage—in a manner
analogous to the way malloc()
allocates memory from the
heap—with the function cvMemStorageAlloc()
. In this case
you simply provide a pointer to the storage and the number of bytes you need. The return is
a pointer of type void*
(again, similar to malloc()
).
[102] Actually, one other function, called cvRestoreMemStoragePos()
, can restore memory to the storage. But this
function is primarily for the library's internal use and is beyond the scope of this
book.