Chapter 3. Getting to Know OpenCV Data Types

The Basics

In the next few chapters, we will see all of the basic data types of OpenCV, from the primitives to the larger structures that are used to handle arrays such as images and large matrices. Along the way, we will also cover the vast menagerie of functions that allow us to manipulate this data in a host of useful ways. In this chapter, we will start out by learning about the basic data types and will cover some useful utility functions that the library provides.

OpenCV Data Types

OpenCV has many data types, which are designed to make the representation and handling of important computer vision concepts relatively easy and intuitive. At the same time, many algorithm developers require a set of relatively powerful primitives that can be generalized or extended for their particular needs. This library attempts to address both of these needs through the use of templates for fundamental data types, and specializations of those templates that make everyday operations easier.

From an organizational perspective, it is convenient to divide the data types into three major categories. First, the basic data types are those that are assembled directly from C++ primitives (int, float, etc.). These types include simple vectors and matrices, as well as representations of simple geometric concepts like points, rectangles, sizes, and the like. The second category contains helper objects. These objects represent more abstract concepts such as the garbage-collecting pointer class, range objects used for slicing, and abstractions such as termination criteria. The third category is what might be called large array types. These are objects whose fundamental purpose is to contain arrays or other assemblies of primitives or, more often, the basic data types. The star example of this category is the cv::Mat class, which is used to represent arbitrary-dimensional arrays containing arbitrary basic elements. Objects such as images are specialized uses of the cv::Mat class, but—unlike in earlier versions of OpenCV (i.e., before version 2.1)—such specific use does not require a different class or type. In addition to cv::Mat, this category contains related objects  such as the sparse matrix cv::SparseMat class, which is more naturally suited to nondense data such as histograms. The cv::Mat and cv::SparseMat classes will be the subjects of the next chapter.

In addition to these types, OpenCV also makes heavy use of the Standard Template Library (STL). OpenCV particularly relies on the vector class, and many OpenCV library functions now have vector template objects in their argument lists. We will not cover STL in this book,1 other than as necessary to explain relevant functionality. If you are already comfortable with STL, many of the template mechanisms used “under the hood” in OpenCV will be familiar to you.

Overview of the Basic Types

The most straightforward of the basic data types is the template class cv::Vec<>, a container class for primitives,2 which we will refer to as the fixed vector classes. Why not just use STL classes? The key difference is that the fixed vector classes are intended for small vectors whose dimensions are known at compile time. This allows for particularly efficient code to handle small common operations. What “small” means in practice is that if you have more than just a few elements, you are probably using the wrong class. (In fact, as of version 2.2, this number cannot exceed nine in any case.) In the next chapter, we will look at the cv::Mat class, which is the right way to handle big arrays of any number of dimensions, but for now, think of the fixed vector classes as being handy and speedy for little guys.

Even though cv::Vec<> is a template, you will not tend to see or use it in that form most of the time. Instead, there are aliases (typedefs) for common instantiations of the cv::Vec<> template. They have names like cv::Vec2i, cv::Vec3i, and cv::Vec4d (for a two-element integer vector, a three-element integer vector, or a four-element double-precision floating-point vector, respectively). In general, anything of the form cv::Vec{2,3,4,6}{b,w,s,i,f,d} is valid for any combination of two to four dimensions and the six data types.3

In addition to the fixed vector classes, there are also fixed matrix classes. They are associated with the template cv::Matx<>. Just like the fixed vector classes, cv::Matx<> is not intended to be used for large arrays, but rather is designed for the handling of certain specific small matrix operations. In computer vision, there are a lot of 2 × 2 or 3 × 3 matrices around, and a few 4 × 4, which are used for various transformations. cv::Matx<> is designed to hold these sorts of objects. As with cv::Vec<>, cv::Matx<> is normally accessed through aliases of the form cv::Matx{1,2,3,4,6}{1,2,3,4,6}{f,d}. It is important to notice that with the fixed matrix classes (like the fixed vector classes, but unlike next chapter’s cv::Mat), the dimensionality of the fixed matrix classes must be known at compile time. Of course, it is precisely this knowledge that makes operations with the fixed matrix classes highly efficient and eliminates many dynamic memory allocation operations.

Closely related to the fixed vector classes are the point classes, which are containers for two or three values of one of the primitive types. The point classes are derived from their own template, so they are not directly descended from the fixed vector classes, but they can be cast to and from them. The main difference between the point classes and the fixed vector classes is that their members are accessed by named variables (mypoint.x, mypoint.y, etc.) rather than by a vector index (myvec[0], myvec[1], etc.). As with cv::Vec<>, the point classes  are typically invoked via aliases for the instantiation of an appropriate template. Those aliases have names like cv::Point2i, cv::Point2f, and cv::Point2d, or cv::Point3i, cv::Point3f, and cv::Point3d.

The class cv::Scalar is essentially a four-dimensional point. As with the point classes, cv::Scalar is actually associated with a template that can generate an arbitrary four-component vector, but the keyword cv::Scalar specifically is aliased to a four-component vector with double-precision components. Unlike the point classes, the elements of a cv::Scalar object are accessed with an integer index, the same as cv::Vec<>. This is because cv::Scalar is directly derived from an instantiation of cv::Vec<> (specifically, from cv::Vec<double,4>).

Next on our tour are cv::Size and cv::Rect. As with the point classes, these two are derived from their own templates. cv::Size is mainly distinguished by having data members width and height rather than x and y, while cv::Rect has all four.  The class cv::Size is actually an  alias for cv::Size2i, which is itself an alias of a more general template in the case of width and height being integers. For floating-point values of width and height, use the alias cv::Size2f. Similarly, cv::Rect is an alias for the integer form of rectangle. There is also a class to represent a rectangle that is not axis-aligned. It is called cv::RotatedRect and contains a cv::Point2f called center, a cv::Size2f called size, and one additional float called angle.

Basic Types: Getting Down to Details

Each of the basic types is actually a relatively complicated object, supporting its own interface functions, overloaded operators, and the like. In this section, we will take a somewhat more encyclopedic look at what each type offers, and how some of the otherwise seemingly similar types differ from one another.

As we go over these classes, we will try to hit the high points of their interfaces, but not get into every gory detail. Instead, we will provide examples that should convey what you can and can’t do with these objects. For the low-level details, you should consult .../opencv2/core/core.hpp.

The point classes

Of the OpenCV basic types, the point classes are probably the simplest. As we mentioned earlier, these are implemented based on a template structure, such that there can be points of any type: integer, floating-point, and so on. There are actually two such templates, one for two-dimensional and one for three-dimensional points. The big advantage of the point classes is that they are simple and have very little overhead. Natively, they do not have a lot of operations defined on them, but they can be cast to somewhat more generalized types, such as the fixed vector classes or the fixed matrix classes (discussed later), when needed.

In most programs, the point classes are instantiated via aliases that take forms like cv::Point2i or cv::Point3f, with the last letter indicating the desired primitive from which the point is to be constructed. (Here, b is an unsigned character, i is a 32-bit integer, f is a 32-bit floating-point number, and d is a 64-bit floating-point number.)

Table 3-1 is the (relatively short) list of functions natively supported by the point classes. Note that there are several very important operations that are supported, but they are supported indirectly through implicit casting to the fixed vector classes (described in “The fixed vector classes”). These operations notably contain all of the vector and singleton4 overloaded algebraic operators and comparison operators.

Table 3-1. Operations supported directly by the point classes
Operation Example
Default constructors
cv::Point2i p;
cv::Point3f p;
Copy constructor
cv::Point3f p2( p1 );
Value constructors
cv::Point2i p( x0, x1 );
cv::Point3d p( x0, x1, x2 );
Cast to the fixed vector classes
(cv::Vec3f) p;
Member access
p.x; p.y; // and for three-dimensional
         // point classes:  p.z
Dot product
float x = p1.dot( p2 )
Double-precision dot product
double x = p1.ddot( p2 )
Cross product
p1.cross( p2 ) // (for three-dimensional point
              // classes only)
Query if point p is inside rectangle r
p.inside( r )  // (for two-dimensional point
              // classes only)

These types can be cast to and from the old C interface types CvPoint and CvPoint2D32f. In cases in which a floating-point-valued instance of one of the point classes is cast to CvPoint, the values will automatically be rounded.

The cv::Scalar class

cv::Scalar is really a four-dimensional point class. Like the others, it is actually associated with a template class, but the alias for accessing it returns an instantiation of that template in which all of the members are double-precision floating-point numbers. The cv::Scalar class also has some special member functions associated with uses of four-component vectors in computer vision. Table 3-2 lists the operations supported by cv::Scalar.

Table 3-2. Operations supported directly by cv::Scalar
Operation Example
Default constructors
cv::Scalar s;
Copy constructor
cv::Scalar s2( s1 );
Value constructors
cv::Scalar s( x0 );
cv::Scalar s( x0, x1, x2, x3 );
Element-wise multiplication
s1.mul( s2 );
(Quaternion) conjugation
s.conj(); // (returns cv::Scalar(s0,-s1,-s2,-s2))
(Quaternion) real test
s.isReal(); // (returns true iff s1==s2==s3==0)

You will notice that for cv::Scalar, the operation “cast to the fixed vector classes” does not appear in Table 3-2 (as it did in Table 3-1). This is because, unlike the point classes, cv::Scalar inherits directly from an instantiation of the fixed vector class template. As a result, it inherits all of the vector algebra operations, member access functions (i.e., operator[]), and other properties from the fixed vector classes. We will get to that class later, but for now, just keep in mind that cv::Scalar is shorthand for a four-dimensional double-precision vector that has a few special member functions attached that are useful for various kinds of four-vectors.

The cv::Scalar class can be freely cast to and from the old C interface CvScalar type.

The size classes

The size classes are, in practice, similar to the corresponding point classes, and can be cast to and from them. The primary difference between the two is that the point classes’ data members are named x and y, while the corresponding data members in the size classes are named width and height. The three aliases for the size classes are cv::Size, cv::Size2i, and cv::Size2f. The first two of these are equivalent and imply integer size, while the last is for 32-bit floating-point sizes. As with the point classes, the size classes can be cast to and from the corresponding old-style OpenCV classes (in this case, CvSize and CvSize2D32f). Table 3-3 lists the operations supported  by  the size classes.

Table 3-3. Operations supported directly by the size classes
Operation Example
Default constructors
cv::Size sz;
cv::Size2i sz;
cv::Size2f sz;
Copy constructor
cv::Size sz2( sz1 );
Value constructors
cv::Size2f sz( w, h );
Member access
sz.width; sz.height;
Compute area
sz.area();

Unlike the point classes, the size classes do not support casting to the fixed vector classes. This means that the size classes have more restricted utility. On the other hand, the point classes and the fixed vector classes can be cast to the size classes without any problem.

The cv::Rect class

The rectangle classes include the members x and y of the point class (representing the upper-left corner of the rectangle) and the members width and height of the size class (representing the rectangle’s size). The rectangle classes, however, do not inherit from the point or size classes, and so in general they do not inherit operators from them (see Table 3-4).

Table 3-4. Operations supported directly by cv::Rect
Operation Example
Default constructors
cv::Rect r;
Copy constructor
cv::Rect r2( r1 );
Value constructors
cv::Rect( x, y, w, h );
Construct from origin and size
cv::Rect( p, sz );
Construct from two corners
cv::Rect( p1, p2 );
Member access
r.x; r.y; r.width; r.height;
Compute area
r.area();
Extract upper-left corner
r.tl();
Extract bottom-right corner
r.br();
Determine if point p is inside rectangle r
r.contains( p );

Cast operators and copy constructors exist to allow cv::Rect to be computed from or cast to the old-style cv::CvRect type as well. cv::Rect is actually an alias for a rectangle template instantiated with integer members.

As Table 3-5 shows, cv::Rect also supports a variety of overloaded operators that can be used for the computation of various geometrical properties of two rectangles or a rectangle and another object.

Table 3-5. Overloaded operators that take objects of type cv::Rect
Operation Example
Intersection of rectangles r1 and r2
cv::Rect r3 = r1 & r2;
r1 &= r2;
Minimum area rectangle containing rectangles r1 and r2
cv::Rect r3 = r1 | r2;
r1 |= r2;
Translate rectangle r by an amount x
cv::Rect rx = r + x;
r += x;
Enlarge a rectangle r by an amount given by size s
cv::Rect rs = r + s;
r += s;
Compare rectangles r1 and r2 for exact equality
bool eq = (r1 == r2);
Compare rectangles r1 and r2 for inequality
bool ne = (r1 != r2);

The cv::RotatedRect class

The cv::RotatedRect class is one of the few classes in the C++ OpenCV interface that is not a template underneath. Instead, it is a container that holds a cv::Point2f called center, a cv::Size2f called size, and one additional float called angle, with the latter representing the rotation of the rectangle around center. One very important difference between cv::RotatedRect and cv::Rect is the convention that a cv::RotatedRect is located in “space” relative to its center, while the cv::Rect is located relative to its upper-left corner. Table 3-6 lists the operations that are supported directly by cv::RotatedRect.

Table 3-6. Operations supported directly by cv::RotatedRect
Operation Example
Default constructors
cv::RotatedRect rr();
Copy constructor
cv::RotatedRect rr2( rr1 );
Construct from two corners
cv::RotatedRect( p1, p2 );
Value constructors; takes a point, a size, and an angle
cv::RotatedRect rr( p, sz, theta ) ;
Member access
rr.center; rr.size; rr.angle;
Return a list of the corners
rr.points( pts[4] );

The fixed matrix classes

The fixed matrix classes are for matrices whose dimensions are known at compile time (hence “fixed”). As a result, all memory for their data is allocated on the stack, which means that they allocate and clean up quickly. Operations on them are fast, and there are specially optimized implementations for small matrices (2 × 2, 3 × 3, etc.). The fixed matrix classes are also central to many of the other basic types in the C++ interface to OpenCV. The fixed vector class derives from the fixed matrix classes, and other classes either derive from the fixed vector class (like cv::Scalar) or they rely on casting to the fixed vector class for many important operations. As usual, the fixed matrix classes are really a template. The template is called cv::Matx<>, but individual matrices are usually allocated through aliases. The basic form of such an alias is cv::Matx{1,2,...}{1,2,...}{f,d}, where the numbers can be any number from one to six, and the trailing letter has the same meaning as with the previous types.5

In general, you should use the fixed matrix classes when you are representing something that is really a matrix with which you are going to do matrix algebra. If your object is really a big data array, like an image or a huge list of points, the fixed matrix classes are not the correct solution; you should be using cv::Mat (which we will get to in the next chapter). Fixed matrix classes are for small matrices where you know the size at compile time (e.g., a camera matrix).  Table 3-7 lists the operations supported by cv::Matx.

Table 3-7. Operations supported by cv::Matx
Operation Example
Default constructor
cv::Matx33f m33f; cv::Matx43d m43d;
Copy constructor
cv::Matx22d m22d( n22d );
Value constructors
cv::Matx21f m(x0,x1); cv::Matx44d
m(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15);
Matrix of identical elements
m33f = cv::Matx33f::all( x );
Matrix of zeros
m23d = cv::Matx23d::zeros();
Matrix of ones
m16f = cv::Matx16f::ones();
Create a unit matrix
m33f = cv::Matx33f::eye();
Create a matrix that can hold the diagonal of another
m31f = cv::Matx33f::diag(); // Create a matrix of
                          // size 3-by-1 of floats
Create a matrix with uniformly distributed entries
m33f = cv::Matx33f::randu( min, max );
Create a matrix with normally distributed entries
m33f = cv::Matx33f::nrandn( mean, variance );
Member access
m( i, j ), m( i ); // one argument for
                  // one-dimensional matrices only
Matrix algebra
m1 = m0; m0 * m1; m0 + m1; m0 – m1;
Singleton algebra
m * a; a * m; m / a;
Comparison
m1 == m2; m1 != m2;
Dot product
m1.dot( m2 );  // (sum of element-wise
              // multiplications, precision of m)
Dot product
m1.ddot( m2 ); // (sum of element-wise multiplications,
              // double precision)
Reshape a matrix
m91f = m33f.reshape<9,1>();
Cast operators
m44f = (Matx44f) m44d
Extract 2 × 2 submatrix at (i, j)
m44f.get_minor<2, 2>( i, j );
Extract row i
m14f = m44f.row( i );
Extract column j
m41f = m44f.col( j );
Extract matrix diagonal
m41f = m44f.diag();
Compute transpose
n44f = m44f.t();
Invert matrix
n44f = m44f.inv( method ); // (default method is
                         // cv::DECOMP_LU)
Solve linear system
m31f = m33f.solve( rhs31f, method )
m32f = m33f.solve<2>( rhs32f, method ); // (template forma);
                                     // default method is DECOMP_LU)
Per-element multiplication
m1.mul( m2 );

a The template form is used when the righthand side of the implied matrix equation has multiple columns. In this case, we are essentially solving for k different systems at once. This value of k must be supplied as the template argument to solve<>(). It will also determine the number of columns in the result matrix.

Note that many of the fixed matrix functions are static relative to the class (i.e., you access them directly as members of the class rather than as members of a particular object). For example, if you would like to construct a 3 × 3 identity matrix, you have a handy class function for it: cv::Mat33f::eye(). Note that, in this example, eye() does not need any arguments because it is a member of the class, and the class is already a specialization of the cv::Matx<> template to 3 × 3.

The fixed vector classes

The fixed vector classes are derived from the fixed matrix classes. They are really just convenience functions for cv::Matx<>. In the proper sense of C++ inheritance, it is correct to say that the fixed vector template cv::Vec<> is a cv::Matx<> whose number of columns is one.  The readily available aliases for specific instantiations of cv::Vec<> are of the form cv::Vec{2,3,4,6}{b,s,w,i,f,d}, where the last character has the usual meanings (with the addition of w, which indicates an unsigned short).  Table 3-8 shows the operations cv::Vec supports.  

Table 3-8. Operations supported by cv::Vec
Operation Example
Default constructor
Vec2s v2s; Vec6f v6f; // etc...
Copy constructor
Vec3f u3f( v3f );
Value constructors
Vec2f v2f(x0,x1); Vec6d v6d(x0,x1,x2,x3,x4,x5);
Member access
v4f[ i ]; v3w( j ); // (operator() and operator[]
                   // both work)
Vector cross-product
v3f.cross( u3f );

The primary conveniences of the fixed vector classes are the ability to access elements with a single ordinal, and a few specific additional functions that would not make sense for a general matrix (e.g., cross product). We can see this in Table 3-8 by the relatively small number of novel methods added to the large number of methods inherited from the fixed matrix classes.

The complex number classes

One more class type should be included in the basic types: the complex number classes. The OpenCV complex number classes are not identical to, but are compatible with—and can be cast to and from—the classes associated with the STL complex number class template complex<>. The most substantial difference between the OpenCV and STL complex number classes is in member access. In the STL classes, the real and imaginary parts are accessed through the member functions real() and imag(), while in the OpenCV class, they are directly accessible as (public) member variables re and im. Table 3-9 lists the operations supported by the complex number classes.

Table 3-9. Operations supported by the OpenCV complex number classes
Operation Example
Default constructor
cv::Complexf z1; cv::Complexd z2;
Copy constructor
cv::Complexf z2( z1 );
Value constructors
cv::Complexd z1(re0); cv::Complexd(re0,im1) ;
Copy constructor
cv::Complexf u2f( v2f );
Member access
z1.re; z1.im;
Complex conjugate
z2 = z1.conj();

Like many basic types, the complex classes are aliases for underlying templates. cv::Complexf and cv::Complexd are aliases for single- and double-precision complex numbers, respectively.

Helper Objects

In addition to the basic types and the big  containers (which we will get to in the next section), there is a family of helper objects that are important for controlling various algorithms (such as termination criteria) or for doing various operations on the containers (such as “ranges” or “slices”). There is also one very important object, the “smart” pointer object cv::Ptr. Looking into cv::Ptr, we will examine the garbage-collecting system, which is integral to the C++ interface to OpenCV. This system frees us from worrying about the details of object allocation and deallocation in the manner that was so onerous in the earlier C-based OpenCV interface (i.e., before version 2.1).

The cv::TermCriteria class

Many algorithms require a stopping condition to know when to quit. Generally, stopping criteria take the form of either some finite number of iterations that are allowed (called COUNT or MAX_ITER) or some kind of error parameter that basically says, “if you are this close, you can quit” (called EPS—short for epsilon, everyone’s favorite tiny number). In many cases, it is desirable to have both of these at once so that if the algorithm never gets “close enough,” it will still quit at some point.

The cv::TermCriteria objects encapsulate one or both of the stopping criteria so that they can be passed conveniently to an OpenCV algorithm function. They have three member variables—type, maxCount, and epsilon—which can be set directly (they are public) or, more often, are just set by the constructor with the form TermCriteria( int type, int maxCount, double epsilon ). The variable type is set to either cv::TermCriteria::COUNT or TermCriteria::EPS. You can also “or” (i.e., |) the two together. The value cv::TermCriteria::COUNT is a synonym for cv::TermCriteria::MAX_ITER, so you can use that if you prefer. If the termination criterion includes cv::TermCriteria::COUNT, then you are telling the algorithm to terminate after maxCount iterations. If the termination criterion includes cv::TermCriteria::EPS, then you are telling the algorithm to terminate after some metric associated with the algorithm’s convergence falls below epsilon.6 The type argument has to be set accordingly for maxCount or epsilon to be used.

The cv::Range class

The cv::Range class is used to specify a continuous sequence of integers. cv::Range objects have two elements, start and end, which—similar to cv::TermCriteria—are often set with the constructor cv::Range( int start, int end ). Ranges are inclusive of their start value, but not inclusive of their end value, so cv::Range rng( 0, 4 ) includes the values 0, 1, 2, and 3, but not 4.

Using size(), you can find the number of elements in a range. In the preceding example, rng.size() would be equal to 4. There is also a member, empty(), that tests if a range has no elements. Finally, cv::Range::all() can be used anywhere a range is required to indicate whatever range the object has available.

The cv::Ptr template and Garbage Collection 101

One very useful object type in C++ is the “smart” pointer.7 This pointer allows us to create a reference to something, and then pass it around. You can create more references to that thing, and then all of those references will be counted. As references go out of scope, the reference count for the smart pointer is decremented. Once all of the references (instances of the pointer) are gone, the “thing” will automatically be cleaned up (deallocated). You, the programmer, don’t have to do this bookkeeping anymore.

Here’s how this all works. First, you define an instance of the pointer template for the class object that you want to “wrap.” You do this with a call like cv::Ptr<Matx33f> p( new cv::Matx33f ), or cv::Ptr<Matx33f> p = makePtr<cv::Matx33f>(). The constructor for the template object takes a pointer to the object to be pointed to. Once you do this, you have your smart pointer p, which is a sort of pointer-like object that you can pass around and use just like a normal pointer (i.e., it supports operators such as operator*() and operator->()). Once you have p, you can create other objects of the same type without passing them a pointer to a new object. For example, you could create Ptr<Mat33f> q, and when you assign the value of p to q, somewhere behind the scenes, the “smart” action of the smart pointer comes into play. You see, just like a usual pointer, there is still only one actual cv::Mat33f object out there that p and q both point to. The difference is that both p and q know that they are each one of two pointers. Should p disappear (such as by falling out of scope), q knows that it is the only remaining reference to the original matrix. If q should then disappear and its destructor is called (implicitly), q will know that is the last one left, and that it should deallocate the original matrix. You can think of this like the last person out of a building being responsible for turning out the lights and locking the door (and in this case, burning the building to the ground as well).

The cv::Ptr<> template class supports several additional functions in its interface related to the reference-counting functionality of the smart pointer. Specifically, the functions addref() and release() increment and decrement the internal reference counter of the pointer. These are relatively dangerous functions to use, but are available in case you need to micromanage the reference counters yourself.

There is also a function called empty(), which you can use to determine if a smart pointer is pointing to an object that has been deallocated. This could happen if you called release() on the object one or more times. In this case, you would still have a smart pointer around, but the object pointed to might already have been destroyed. There is a second application of empty(), which is to determine if the internal object pointer inside the smart pointer object happens to be NULL for some other reason. For example, this might occur if you assigned the smart pointer by calling a function that might just return NULL in the first place (cvLoadImage(), fopen(), etc.).8

The final member of Ptr<> that you will want to know about is delete_obj(). This is a function that gets called automatically when the reference count gets to zero. By default, this function is defined but does nothing. It is there so that you can overload it in the case of instantiation of cv::Ptr<>, which points to a class that requires some specific operation in order to clean up the class to which it points. For example, let’s say that you are working with an old-style (pre–version 2.1) IplImage.9 In the old days, you might, for example, have called cvLoadImage() to load that image from disk. In the C interface, that would have looked like this:

IplImage* img_p = cvLoadImage( ... );

The modern version of this (while still using IplImage rather than cv::Mat, which we are still working our way up to) would look like this:

cv::Ptr<IplImage> img_p = cvLoadImage( "an_image" );

or (if you prefer) this:

cv::Ptr<IplImage> img_p( cvLoadImage("an_image" ) );

Now you can use img_p in exactly the same way as a pointer (which is to say, for readers experienced with the pre–version 2.1 interface, “exactly as you would have back then”). Conveniently, this particular template instantiation is actually already defined for you somewhere in the vast sea of header files that make up OpenCV. If you were to go search it out, you would find the following template function defined:

template<> inline void cv::Ptr<IplImage>::delete_obj() {
    cvReleaseImage(&obj);
}

(The variable obj is the name of the class member variable inside Ptr<> that actually holds the pointer to the allocated object.) As a result of this definition, you will not need to deallocate the IplImage* pointer you got from cvLoadImage(). Instead, it will be automatically deallocated for you when img_p falls out of scope.

This example was a somewhat special (though highly relevant) situation, in that the case of a smart pointer to IplImage is sufficiently salient that it was defined for you by the library. In a somewhat more typical case, when the clean-up function does not exist for what you want, you will have to define it yourself. Consider the example of creating a file handle using a smart pointer to FILE.10 In this case, we define our own overloaded version of delete_obj() for the cv::Ptr<FILE> template:

template<> inline void cv::Ptr<FILE>::delete_obj() {
    fclose(obj);
}

Then you could go ahead and use that pointer to open a file, do whatever with it, and later, just let the pointer fall out of scope (at which time the file handle would automatically be closed for you):

{
  cv::Ptr<FILE> f(fopen("myfile.txt", "r"));
  if(f.empty())
    throw ...;        // Throw an exception, we will get to this later on...
  fprintf(f, ...);
  ...
}

At the final brace, f falls out of scope, the internal reference count in f goes to zero, delete_obj() is called by f’s destructor, and (thus) fclose() is called on the file handle pointer (stored in obj).

Note

A tip for gurus: a serious programmer might worry that the incrementing and decrementing of the reference count might not be sufficiently atomic for the Ptr<> template to be safe in multithreaded applications. This, however, is not the case, and Ptr<> is thread safe. Similarly, the other reference-counting objects in OpenCV are all thread safe in this same sense.

The cv::Exception class and exception handling

OpenCV uses exceptions to handle errors. OpenCV defines its own exception type, cv::Exception, which is derived from the STL exception class std::exception. Really, this exception type has nothing special about it, other than being in the cv:: namespace and thus distinguishable from other objects that are also derived from std::exception.

The type cv::Exception has members code, err, func, file, and line, which are (respectively) a numerical error code, a string indicating the nature of the error that generated the exception, the name of the function in which the error occurred, the file in which the error occurred, and an integer indicating the line on which the error occurred in that file. err, func, and file are all STL strings.

There are several built-in macros for generating exceptions yourself. CV_Error( errorcode, description ) will generate and throw an exception with a fixed text description. CV_Error_( errorcode, printf_fmt_str, [printf-args] ) works the same, but allows you to replace the fixed description with a printf-like format string and arguments. Finally, CV_Assert( condition ) and CV_DbgAssert( condition ) will both test your condition and throw an exception if the condition is not met. The latter version, however, will only operate in debug builds. These macros are the strongly preferred method of throwing exceptions, as they will automatically take care of the fields func, file, and line for you.

The cv::DataType<> template

When OpenCV library functions need to communicate the concept of a particular data type, they do so by creating an object of type cv::DataType<>. cv::DataType<> itself is a template, and so the actual objects passed around are specializations of this template. This is an example of what in C++ are generally called traits. This allows the cv::DataType<> object to contain both runtime information about the type, as well as typedef statements in its own definition that allow it to refer to the same type at compile time. 

This might sound a bit confusing, and it is, but that is an inevitable consequence of trying to mix runtime information and compile-time information in C++.11 An example will help clarify. Here’s the template class definition for DataType:

template<typename _Tp> class DataType
{
  typedef _Tp        value_type;
  typedef value_type work_type;
  typedef value_type channel_type;
  typedef value_type vec_type;

  enum {
    generic_type = 1,
    depth        = -1,
    channels     = 1,
    fmt          = 0,
    type         = CV_MAKETYPE(depth, channels)
  };
};

Let’s try to understand what this means, and then follow it with an example. First, we can see that cv::DataType<> is a template, and expects to be specialized to a class called _Tp. It then has four typedef statements that allow the type of the cv::DataType<>, as well as some other related types, to be extracted from the cv::DataType<> instantiated object at compile time. In the template definition, these are all the same, but we will see in our example of a template specialization that they do not have to be (and often should not be). The next section is an enum that contains several components.12 These are the generic_type, the depth, the number of channels, the format fmt, and the type. To see what all of these components mean, we’ll look at two example specializations of cv::DataType<>, from core.hpp. The first is the cv::DataType<> definition for float:

template<> class DataType<float>
{
public:
  typedef float      value_type;
  typedef value_type work_type;
  typedef value_type channel_type;
  typedef value_type vec_type;

  enum {
    generic_type = 0,
    depth        = DataDepth<channel_type>::value,
    channels     = 1,
    fmt          = DataDepth<channel_type>::fmt,
    type         = CV_MAKETYPE(depth, channels)
  };
};

The first thing to notice is that this is a definition for a C++ built-in type. It is useful to have such definitions for the built-in types, but we can also make them for more complicated objects. In this case, the value_type is of course float, and the work_type, channel_type, and vec_type are all the same. We will see more clearly what these are for in the next example. For the constants in the enum, this example will do just fine. The first variable, generic_type, is set to 0, as it is zero for all types defined in core.hpp. The depth variable is the data type identifier used by OpenCV. For example, cv::DataDepth<float>::value resolves to the constant CV_32F. The entry channels is 1 because float is just a single number; we will see an alternative to this in the next example. The variable fmt gives a single-character representation of the format. In this case, cv::DataDepth<float>::fmt resolves to f. The last entry is type, which is a representation similar to depth, but includes the number of channels (in this case, one). CV_MAKETYPE(CV_32F,1) resolves to CV_32FC1.

The important thing about DataType<>, however, is to communicate the nature of more complicated constructs. This is essential, for example, for allowing algorithms to be implemented in a manner that is agnostic to the incoming data type (i.e., algorithms that use introspection to determine how to proceed with incoming data).

Consider the example of an instantiation of cv::DataType<> for a cv::Rect<> (itself containing an as-yet-unspecialized type _Tp):

template<typename _Tp> class DataType<Rect_<_Tp> >
{
public:
  typedef Rect_<_Tp>                               value_type;
  typedef Rect_<typename DataType<_Tp>::work_type> work_type;
  typedef _Tp                                      channel_type;
  typedef Vec<channel_type, channels>              vec_type;

  enum {
    generic_type = 0,
    depth        = DataDepth<channel_type>::value,
    channels     = 4,
    fmt          = ((channels-1)<<8) + DataDepth<channel_type>::fmt,
    type         = CV_MAKETYPE(depth, channels)
  };
};

This is a much more complicated example. First, notice that cv::Rect itself does not appear. You will recall that earlier we mentioned that cv::Rect was actually an alias for a template, and that template is called cv::Rect_<>. So this template could be specialized as cv::DataType<Rect> or, for example, cv::DataType< Rect_<float> >. For the case cv::DataType<Rect>, recall that all of the elements are integers, so if we consider that case, all of the instantiations of the template parameter _Tp resolve to int.

We can see that the value_type is just the compile-time name of the thing that the cv::DataType<> is describing (namely Rect). The work_type, however, is defined to be the work_type of cv::DataType<int> (which, not surprisingly, is int). What we see is that the work_type is telling us what kind of variables the cv::DataType<> is made of (i.e., what we “do work” on). The channel type is also int. This means that if we want to represent this variable as a multichannel object, it should be represented as some number of int objects. Finally, just as channel_type tells us how to represent this cv::DataType<> as a multichannel object, vec_type tells us how to represent it as an object of type cv::Vec<>. The alias cv::DataType<Rect>::vec_type will resolve to cv::Vec<int,4>.

Moving on to the runtime constants: generic_type is again 0, depth is CV_32S, channels is 4 (because there are actually four values, the same reason the vec_type instantiated to a cv::Vec<> of size 4), fmt resolves to 0x3069 (since i is 0x69), and type resolves to CV_32SC4.

The cv::InputArray and cv::OutputArray classes

Many OpenCV functions take arrays as arguments and return arrays as return values, but in OpenCV, there are many kinds of arrays. We have already seen that OpenCV supports some small array types (cv::Scalar, cv::Vec, cv::Matx) and STL’s std::vector<> in addition to the large array types discussed in the next chapter (cv::Mat and cv::SparseMat). In order to keep the interface from becoming onerously complicated (and repetitive), OpenCV defines the types cv::InputArray and cv::OutputArray. In effect, these types mean “any of the above” with respect to the many array forms supported by the library. There is even a cv::InputOutputArray, specifying an array for in-place computation.

The primary difference between cv::InputArray and cv::OutputArray is that the former is assumed to be const (i.e., read only). You will typically see these two types used in the definitions of library routines. You will not tend to use them yourself, but when you are being introduced to library functions, their presence means that you can use any array type, including a single cv::Scalar, and the result should be what you expect.

Related to cv::InputArray is the special function cv::noArray() that returns a cv::InputArray. The returned object can be passed to any input requiring cv::Inpu⁠t​Array to indicate that this input is not being used. Certain functions also have optional output arrays, where you may pass cv::noArray() when you do not need the corresponding output.

Utility Functions

In addition to providing the specialized primitive data types that we have seen so far in this chapter, the OpenCV library also provides some specialized functions that can be used to more efficiently handle mathematical and other operations which arise commonly in computer vision applications. In the context of the library, these are known as the utility functions. The utility functions include tools for mathematical operations, tests, error generations, memory and thread handling, optimization, and more. Table 3-10 lists these functions and summarizes their functionalities; detailed descriptions then follow.

Table 3-10. Utility and system functions
Function Description
cv::alignPtr() Align pointer to given number of bytes
cv::alignSize() Align buffer size to given number of bytes
cv::allocate() Allocate a C-style array of objects
cvCeil() a Round float number x to nearest integer not smaller than x
cv::cubeRoot() Compute the cube root of a number
cv::CV_Assert() Throw an exception if a given condition is not true
CV_Error() Macro to build a cv::Exception (from a fixed string) and throw it
CV_Error_() Macro to build a cv::Exception (from a formatted string) and throw it
cv::deallocate() Deallocate a C-style array of objects
cv::error() Indicate an error and throw an exception
cv::fastAtan2() Calculate two-dimensional angle of a vector in degrees
cv::fastFree() Deallocate a memory buffer
cv::fastMalloc() Allocate an aligned memory buffer
cvFloor() Round float number x to nearest integer not larger than x
cv::format() Create an STL string using sprintf-like formatting
cv::getCPUTickCount() Get tick count from internal CPU timer
cv::getNumThreads() Count number of threads currently used by OpenCV
cv::getOptimalDFTSize() Compute the best size for an array that you plan to pass to cv::DFT()
cv::getThreadNum() Get index of the current thread
cv::getTickCount() Get tick count from system
cv::getTickFrequency() Get number or ticks per second (see cv::getTickCount())
cvIsInf() Check if a floating-point number x is infinity
cvIsNaN() Check if a floating-point number x is “Not a Number”
cvRound() Round float number x to the nearest integer
cv::setNumThreads() Set number of threads used by OpenCV
cv::setUseOptimized() Enables or disables the use of optimized code (SSE2, etc.)
cv::useOptimized() Indicates status of optimized code enabling (see cv::setUseOptimized())

a This function has something of a legacy interface. It is a C definition, not C++ (see core .../types_c.h) where it is defined as an inline function. There are several others with a similar interface.

cv::alignPtr()

template<T> T* cv::alignPtr(              // Return aligned pointer of type T*
  T*  ptr,                                // pointer, unaligned
  int n   = sizeof(T)                     // align to block size, a power of 2
);

Given a pointer of any type, this function computes an aligned pointer of the same type according to the following computation:

(T*)(((size_t)ptr + n+1) & -n)
Note

On some architectures, it is not even possible to read a multibyte object from an address that is not evenly divisible by the size of the object (i.e., by 4 for a 32-bit integer). On architectures such as x86, the CPU handles this for you automatically by using multiple reads and assembling your value from those reads at the cost of a substantial penalty in performance.

cv::alignSize()

size_t cv::alignSize(                     // minimum size >='sz' divisible by 'n'
  size_t sz,                              // size of buffer
  int n   = sizeof(T)                     // align to block size, a power of 2
);

Given a number n (typically a return value from sizeof()), and a size for a buffer sz, cv::alignSize() computes the size that this buffer should be in order to contain an integer number of objects of size n—that is, the minimum number that is greater or equal to sz yet divisible by n. The following formula is used:

(sz + n-1) & -n

cv::allocate()

template<T> T* cv::allocate(              // Return pointer to allocated buffer
  size_t sz                               // buffer size, multiples of sizeof(T)
);

The function cv::allocate() functions similarly to the array form of new, in that it allocates a C-style array of n objects of type T, calls the default constructor for each object, and returns a pointer to the first object in the array.

cv::deallocate()

template<T> void cv::deallocate(
  T*     ptr,                         // Pointer to buffer to free
  size_t sz                           // size of buffer, multiples of sizeof(T)
);

The function cv::deallocate() functions similarly to the array form of delete, in that it deallocates a C-style array of n objects of type T, and calls the destructor for each object. cv::deallocate() is used to deallocate objects allocated with cv::allocate(). The number of elements n passed to cv::deallocate() must be the same as the number of objects originally allocated with cv::allocate().

cv::fastAtan2()

float cv::fastAtan2(                      // Return value is 32-bit float
  float y,                                // y input value (32-bit float)
  float x                                 // x input value (32-bit float)
);

This function computes the arctangent of an x,y pair and returns the angle from the origin to the indicated point. The result is reported in degrees ranging from 0.0 to 360.0, inclusive of 0.0 but not inclusive of 360.0.

cvCeil()

int cvCeil(                               // Return the smallest int >= x
  float x                                 // input value (32-bit float)
);

Given a floating-point number x, cvCeil() computes the smallest integer not smaller than x. If the input value is outside of the range representable by a 32-bit integer, the result is undefined.

cv::cubeRoot()

float cv::cubeRoot(                       // Return value is 32-bit float
  float x                                 // input value (32-bit float)
);

This function computes the cubed root of the argument x. Negative values of x are handled correctly (i.e., the return value is negative).

cv::CV_Assert() and CV_DbgAssert()

// example
CV_Assert( x!=0 )

CV_Assert() is a macro that will test the expression passed to it and, if that expression evaluates to False (or 0), it will throw an exception. The CV_Assert() macro is always tested.  Alternatively, you can use CV_DbgAssert(), which will be tested only in debug  compilations.

cv::CV_Error() and CV_Error_()

// example
CV_Error( ecode, estring )
CV_Error_( ecode, fmt, ... )

The macro CV_Error() allows you to pass in an error code ecode and  a fixed C-style character string estring, which it then packages up into a cv::Exception that it then passes to cv::error() to be handled. The variant macro CV_Error_() is used if you need to construct the message string on the fly. CV_Error_() accepts the same ecode as CV_Error(), but  then expects a sprintf()-style format string followed by a variable number of arguments, as would be expected by sprintf().

cv::error()

void cv::error(
  const cv::Exception& ex                 // Exception to be thrown
);

This function is mostly called from CV_Error() and CV_Error_(). If your code is compiled in a nondebug build, it will throw the exception ex. If your code is compiled in a debug build, it will deliberately provoke a memory access violation so that the execution stack and all of the parameters will be available for whatever debugger you are running.

You will probably not call cv::error() directly, but rather rely on the macros CV_Error() and CV_Error_() to throw the error for you. These macros take the information you want displayed in the exception, package it up for you, and pass the resulting exception to cv::error().

cv::fastFree()

void cv::fastFree(
  void* ptr                               // Pointer to buffer to be freed
);

This routine deallocates buffers that were allocated with cv::fastMalloc() (covered next).

cv::fastMalloc()

void* cv::fastMalloc(                     // Pointer to allocated buffer
  size_t size                             // Size of buffer to allocate
);

cv::FastMalloc() works just like the malloc() you are familiar with, except that it is often faster, and it does buffer size alignment for you. This means that if the buffer size passed is more than 16 bytes, the returned buffer will be aligned to a 16-byte boundary.

cvFloor()

int cvFloor(                              // Return the largest int <= x
  float x                                 // input value (32-bit float)
};

Given a floating-point number x, cv::Floor() computes the largest integer not larger than x. If the input value is outside of the range representable by a 32-bit integer, the result is undefined.

cv::format()

string cv::format(                        // Return STL-string
  const char* fmt,                        // formatting string, as sprintf()
  ...                                     // vargs, as sprintf()
);

This function is essentially the same as sprintf() from the standard library, but rather than requiring a character buffer from the caller, it constructs an STL string object and returns that. It is particularly handy for formatting error messages for the Exception() constructor (which expects STL strings in its arguments).

cv::getCPUTickCount()

int64 cv::getCPUTickCount( void );        // long int CPU for tick count

This function reports the number of CPU ticks on those architectures that have such a construct (including, but not limited to, x86 architectures). It is important to know, however, that the return value of this function can be very difficult to interpret on many architectures. In particular, because on a multicore system a thread can be put to sleep on one core and wake up on another, the difference between the results to two subsequent calls to cv::getCPUTickCount() can be misleading or completely meaningless. Therefore, unless you are certain you know what you are doing, it is best to use cv::getTickCount() for timing measurements.13 This function is best for tasks like initializing random number generators.

cv::getNumThreads()

int cv::getNumThreads( void );            // total threads allocated to OpenCV

Return the current number of threads being used by OpenCV.

cv::getOptimalDFTSize()

int cv::getOptimalDFTSize( int n );       // best size array to use for dft, >= n

When you are making calls to cv::dft(), the algorithm used by OpenCV to compute the transform is extremely sensitive to the size of the array passed to cv::dft(). The preferred sizes do obey a rule for their generation, but that rule is sufficiently complicated that it is (at best) an annoyance to compute the correct size to which to pad your array every time. The function cv::getOptimalDFTSize() takes as an argument the size of the array you would have passed to cv::dft(), and returns the size of the array you should pass to cv::dft(). OpenCV uses this information to create a larger array into which you can copy your data and pad out the rest with zeros.

cv::getThreadNum()

int cv::getThreadNum( void );             // int, id of this particular thread

If your OpenCV library was compiled with OpenMP support, it will return the index (starting from zero) of the currently executing thread.

cv::getTickCount()

int64 cv::getTickCount( void );           // long int CPU for tick count

This function returns a tick count relative to some architecture-dependent time. The rate of ticks is also architecture and operating system dependent, however; the time per tick can be computed by cv::getTickFrequency() (described next). This function is preferable to cv::getCPUTickCount() for most timing applications, as it is not affected by low-level issues such as which core your thread is running on and automatic throttling of CPU frequency (which most modern processors do for power-management reasons).

cv::getTickFrequency()

double cv::getTickFrequency( void );      // Tick frequency in seconds as 64-bit

When cv::getTickCount() is used for timing analysis, the exact meaning of a tick is, in general, architecture dependent. The function cv::getTickFrequency() computes the conversion between clock time (i.e., seconds) and abstract “ticks.”

Note

To compute the time required for some specific thing to happen (such as a function to execute), you need only call cv::getTickCount() before and after the function call, subtract the results, and divide by the value of cv::getTickFrequency().

cvIsInf()

int cvIsInf( double x );              // return 1 if x is IEEE754 "infinity"

The return value of cvIsInf() is 1 if x is plus or minus infinity and 0 otherwise. The infinity test is the test implied by the IEEE754 standard.

cvIsNaN()

int cvIsNan( double x );              // return 1 if x is IEEE754 "Not a number"

The return value of cvIsNaN() is 1 if x is “not a number” and 0 otherwise. The NaN test is the test implied by the IEEE754 standard.

cvRound()

int cvRound( double x );              // Return integer nearest to 'x'

Given a floating-point number x, cvRound() computes the integer closest to x. If the input value is outside of the range representable by a 32-bit integer, the result is undefined. In OpenCV 3.0 there is overloaded cvRound( float x ) (as well as cvFloor and cvCeil), which is faster on ARM.

cv::setNumThreads()

void cv::setNumThreads( int nthreads );   // Set number of threads OpenCV can use

When OpenCV is compiled with OpenMP support, this function sets the number of threads that OpenCV will use in parallel OpenMP regions. The default value for the number of threads is the number of logical cores on the CPU (i.e., if we have four cores each with two hyperthreads, there will be eight threads by default). If nthreads is set to 0, the number of threads will be returned to this default value.

cv::setUseOptimized()

void cv::setUseOptimized( bool on_off ); // If false, turn off optimized routines

Though early versions of OpenCV relied on outside libraries (such as IPP, the Intel Performance Primitives library) for access to high-performance optimizations such as SSE2 instructions, later versions have increasingly moved to containing that code in the OpenCV itself. By default, the use of these optimized routines is enabled, unless you specifically disabled it when you built your installation of the library. However, you can turn the use of these optimizations on and off at any time with cv::setUseOptimized().

Note

The test of the global flag for optimizations usage is done at a relatively high level inside the OpenCV library functions. The implication is that you should not call cv::setUseOptimized() while any other routines might be running (on any threads). You should make sure to call this routine only when you can be certain you know what is and what is not running, preferably from the very top level of your application.

cv::useOptimized()

bool cv::useOptimized( void );    // return true if optimizations are enabled

At any time, you can check the state of the global flag, which enables the use of high-performance optimizations (see cv::setUseOptimized()) by calling cv::useOptimized(). True will be returned only if these optimizations are currently enabled; otherwise, this function will return False.

The Template Structures

Thus far in this chapter, we have regularly alluded to the existence of template forms for almost all of the basic types. In fact, most programmers can get quite far into OpenCV without ever digging down into the templates.14

OpenCV versions 2.1 and later are built on a template metaprogramming style similar to STL, Boost, and similar libraries. This sort of library design can be extremely powerful, both in terms of the quality and speed of the final code, as well as the flexibility it allows the developer. In particular, template structures of the kind used in OpenCV allow for algorithms to be implemented in an abstracted way that does not specifically rely on the primitive types that are native to C++ or even native to OpenCV.

In this chapter, we started with the cv::Point class. Though the class was introduced as a primitive, in fact when you instantiate an object of type cv::Point, you are actually instantiating an even more fundamental template object of type cv::Point_<int>.15 This template could have been instantiated with a different type than int, obviously. In fact, it could have been instantiated with any type that supports the same basic set of operators as int (i.e., addition, subtraction, multiplication, etc.). For example, OpenCV provides a type cv::Complex that you could have used. You also could have used the STL complex type std::complex, which has nothing to do with OpenCV at all. The same is true for some other types of your own construction. This same concept generalizes to other type templates such as cv::Scalar_<> and cv::Rect_<>, as well as cv::Matx_<> and cv::Vec_<>.

When instantiating these templates on your own, you must provide the unitary type that is to be used to compose the template, as well as (where relevant) the dimensions of the template. The arguments to the common templates are shown in Table 3-11.

Table 3-11. Common fixed length templates
Function Description
cv::Point_<Type T> A point consisting of a pair of objects of type T.
cv::Rect_<Type T> A location, width, and height, all of type T.
cv::Vec<Type T, int H> A set of H objects of type T.
cv::Matx<Type T, int H, int W> A set of H*W objects of type T.
cv::Scalar_<Type T> A set of four objects of type T (identical to cv::Vec<T, 4>).

In the next chapter, we will see that the large array types, cv::Mat and cv::SparseMat, also have corresponding template types cv::Mat<> and cv::SparseMat_<>, which are similar but differ in a few important ways.

Summary

In this chapter, we covered in detail the basic data types that are used by the OpenCV library to handle compact collections. These collections include points, but also small vectors and matrices that are often used to represent things like color (channel) vectors or coordinate vectors, as well as small matrices that operate in these spaces. We covered both the template representations used, mostly internally, by the library for such objects, as well as the classes that are specializations of those templates. These specialization classes make up the majority of what you will use on a daily basis.

In addition to these data classes, we also covered the helper objects that allow us to express concepts such as termination criteria and value ranges. Finally, we concluded the chapter by surveying the utility functions that the library provides. These functions provide optimized implementations of important tasks that computer vision applications often encounter. Important examples of operations include special arithmetic and memory management tools.

Exercises

  1. Find and open .../opencv/modules/core/include/opencv2/core/types_c.h. Read through and find the many conversion helper functions.

    1. Choose a negative floating-point number.

    2. Take its absolute value, round it, and then take its ceiling and floor.

    3. Generate some random numbers.

    4. Create a floating-point cv::Point2f and convert it to an integer cv::Point. Convert a cv::Point to a cv::Point2f.

  2. Compact matrix and vector types:

    1. Using the cv::Mat33f and cv::Vec3f objects (respectively), create a 3 × 3 matrix and 3-row vector.

    2. Can you multiply them together directly? If not, why not?

  3. Compact matrix and vector template types:

    1. Using the cv::Mat<> and cv::Vec<> templates (respectively), create a 3 × 3 matrix and 3-row vector.

    2. Can you multiply them together directly? If not, why not?

    3. Try type-casting the vector object to a 3 × 1 matrix, using the cv::Mat<> template. What happens now?

1 Readers unfamiliar with the Standard Template Library can find many excellent references online. In addition, the authors highly recommend Nicolai M. Josuttis’s classic The C++ Standard Library, Second Edition: A Tutorial and Reference (Addison-Wesley, 2012) or Scott Meyers’ excellent Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library (Addison-Wesley, 2001).

2 Actually, this is an oversimplification that we will clear up a little later in the chapter. In fact, cv::Vec<> is a vector container for anything, and uses templating to create this functionality. As a result, cv::Vec<> can contain other class objects, either from OpenCV or elsewhere. In most usages, however, cv::Vec is used as a container for C primitive types like int or float.

3 The six data types referred to here have the following conventional abbreviation in the library: b = unsigned char, w = unsigned short, s = short, i = int, f = float, d = double.

4 You might have expected us to use the word scalar here, but we avoided doing so because cv::Scalar is an existing class in the library. As you will see shortly, a cv::Scalar in OpenCV is (somewhat confusingly) an array of four numbers, approximately equivalent to a cv::Vec with four elements! In this context, the word singleton can be understood to mean “a single object of whatever type the vector is an array of.”

5 At the time of writing, the relevant header file called core.hpp does not actually contain every possible combination of these integers. For example, there is no 1 × 1 matrix alias, nor is there a 5 × 5. This may or may not change in later releases, but you will pretty much never want the missing ones anyway. If you really do want one of the odd ones, you can just instantiate the template yourself (e.g., cv::Matx<5,5,float>).

6 The exact termination criteria are clearly algorithm dependent, but the documentation will always be clear as to how a particular algorithm interprets epsilon.

7 If you are familiar with some of the more recent additions to the C++ standard, you will recognize a similarity between the OpenCV cv::Ptr<> template and the shared_ptr<> template. Similarly, there is a smart pointer shared_ptr<> in the Boost library. Ultimately, they all function more or less the same.

8 For the purposes of this example, we will make reference to IplImage and cvLoadImge(), both constructs from the ancient pre–version 2.1 interface that are now deprecated. We won’t really cover them in detail in this book, but all you need to know for this example is that IplImage is the old data structure for images, and cvLoadImage() was the old function to get an image from disk and return a pointer to the resulting image structure.

9 This example might seem a bit artificial, but in fact, if you have a large body of pre-v2.1 code you are trying to modernize, you will likely find yourself doing an operation like this quite often.

10 In this case, by FILE we mean struct FILE, as defined in the C standard library.

11 You don’t have this sort of problem in languages that support variable introspection and have an intrinsic runtime concept of data types.

12 If this construct is awkward to you, remember that you can always assign integer values to the “options” in an enum declaration. In effect, this is a way of stashing a bunch of integer constants that will be fixed at compile time.

13 Of course, if you really do know what you are doing, then there is no more accurate way to get detailed timing information than from the CPU timers themselves.

14 In fact, if your C++ programming skills are not entirely up to par, you can probably just skim or skip over this little section entirely.

15 Note the trailing underscore—this is a common, but not universal, convention in the library used to indicate a template. In the 2.x version of the library, it was essentially universal. Since 3.x, the underscore was dropped where not specifically necessary. Thus cv::Point_<> still has the underscore to distinguish from the nontemplate class cv::Point, while cv::Vec<> does not have an underscore. (It was cv::Vec_<> in the 2.x version of the library.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset