OpenCV Coding Style Guide
Back to main
-
Foreword
-
File names
-
File structure
-
Naming conventions
-
Designing functions interfaces
-
Implementing functions
-
Code layout
-
Portability
-
Writing documentation on functions
-
Implementing tests for functions
-
Useful tips
-
Appendixes
The document is a short guide on code style, used in OpenCV. The core libraries (cv, cvaux) are written in C/C++, so the document concerns only the codes written in C/C++.
All the file names of cv and cvaux libraries must obey the following rules:
- All the files of CV library have prefix cv.
- Mixed C/C++ interface headers have .h extension
- Pure C++ interface headers have .hpp extension
- Implementation files have .cpp extension
- Names are written all in lower case because of compatibility with POSIX.
Every file starts with BSD-compatible license, which template can be found in Contributors_BSD_License.htm file. Other rules for both header and implementation files include:
- maximal line length is 90 symbols, not including end-of-line characters
- no tabulation used
- indentation is 4 spaces, so the tabulations should be replaced with 1-4 spaces, depending on the starting column
Header files must use guarding macros, protecting the files from repeated inclusion.
Mixed C/C++ interface header files contain extern "C"{}, surrounding C definitions.
Source files must include precomp.h header before other headers, in order to make precompiled headers mechanism in Visual C++ work properly.
Also, look at the samples of header file and implementation file.
OpenCV uses mixed-case style identifiers for external functions, types and class methods.
Macros are written with all capital letters, words are separated by underscore. All the external names or internal names, visible across several files, must have prefixes:
- cv for external functions
- icv for internal functions
- Cv for data structures (C structures, enumerations, unions, classes)
- CV_ for external and some of internal macros
- ICV_ for internal macros.
It is important to design function interface is such a way, consistent with the rest of the library. The elements of function interface include:
- Functionality
- Name
- Return value
- Type of arguments
- Order of arguments
- Default values for some arguments
Functionality must be well defined and non-redundant. The function should be easy embedded into different processing pipelines that use other OpenCV and IPL functions.
Name should be simple to derive it from what the function does. There are a few common naming patterns in OpenCV:
- Majority of function names have form: cv<ActionName><Object>[<Modifiers>], e.g. cvCalibrateCamera, cvCalcOpticalFlowPyrLK. Special pre-defined case is object creation/destroying/clearing without destroying: cvCreate<Object>, cvRelease<Object> and cv<Clear>Object, respectively.
- Sometimes the function may be called by the algorithm name it implements or result object name it produces, e.g. cvSobel, cvCanny, cvRodrigues, cvSqrt, cvGoodFeaturesToTrack.
- In case of the operation on a container element, the function name starts with container type, followed by action name, that may be treated as method name in this case, e.g. SeqPush, GraphAddEdgeByIdx, etc.
Return value should be chosen to simplify function usage. Generally, a function that creates an object should return it. It is the good practice to do so for the functions, producing dynamic data structures or scalar values. However, in case of image processing function it would lead to often allocation/deallocation of large memory blocks, so the image processing functions don't create and return result images rather than modify an output image, passed as a parameter.
Functions should not use return value for signaling about critical errors, such as null pointers, division by zero, bad argument range, unsupported image format etc. There is a special error handling mechanism, similar to that used in IPL, for this purpose. And vice versa, it is better to use return value for signalizing about expected run-time situations (e.g. tracked object goes beyond the screen etc.)
Argument types are preferably chosen from the already existing set of OpenCV types: IplImage for raster images, CvMat for matrices, CvSeq for contours etc. It is not recommended to use plain pointers and counters, because it lowers library interface and makes programs harder to read, because of numerous function parameters.
A consistent argument order is important because it becomes easier to remember the order and it helps programmer to avoid errors, connecting with wrong argument order.
- For simple processing functions (the first and second types in the naming patterns list above) the typical order is: input parameters, output parameters, flags & optional parameters.
- For operations on container elements, the order is: container, element position, flags & optional parameters.
Input parameters usually have const qualifiers.
Optional arguments often simplify function usage. Because C++ allows optional arguments in the end of parameters list only, it also may affect decisions on argument order -the most important flags go first and less important - after. In function declaration use CV_DEFAULT macro for specifying default values of optional arguments. It makes the declaration compatible with C. For example function declaration look at cvexample.h, as well as cv.h and cvaux.h.
The section concerns the following topics:
- Checking argument types
- Error raising and handling
- Memory management and resource deallocation.
- Calling low-level function
As it was said in the previous section, OpenCV functions extensively use high- level data types for passing/returning parameters. It simplifies functions use, but increases probability of calling a function with wrong combination of arguments (e.g. floating-point image instead of byte-depth image, or two images with unmatched sizes).
There exist standard methods for checking arguments of one of standard types.
An IplImage image can be checked via CV_CHECK_IMAGE macro. The macro checks that the passed pointer to IplImage and underlying image data pointer are not NULL, image has pixel order, does not have mask ROI or tiling information.
CV_CHECK_MASK_IMAGE is useful for checking mask images, binary or grayscale images. Besides the conditions CV_CHECK_IMAGE checks, it also ensures that image has 8bit depth and a single channel.
Further, all input and output images should be checked for allowed combinations of depths, channel numbers, sizes. The latter may be checked after calling cvGetImageRawData function that returns an image ROI size.
Input contours and other dynamical data structures can be checked using CV_IS_CONTOUR and related macros.
Whenever bad argument is passed to the function or other critical error happened during the function execution, it should raise an error via function cvError. There is a standard error handling mechanism in OpenCV, similar to IPL the most of all and to the standard C library in less degree. That is, instead of returning error code there exists global error status that can be:
- set using cvError function
- cleared using cvClearErrStatus
- read using cvGetErrorStatus function.
Besides setting the error status to the specified value, cvError can take some additional actions, depending on error processing mode, that can be adjusted via cvSetErrorMode. In silent mode or parent mode cvError returns immediately. In child mode it prints out an error message and then terminate the application. Instead of above functions one can use macros, which are more convenient to use:
- CV_ERROR and OPENCV_ERROR instead of cvError.
- CV_CALL and OPENCV_CALL instead of calling function and checking the status.
CV_* macros require "FuncName" string variable and "exit" label be defined in the function, OPENCV_* don't.
Temporary buffers in OpenCV are allocated using cvAlloc and cvFree functions. The functions take care of proper alignment, keep track on unreleased memory, check buffer overflow. cvAlloc raises an error when the program runs out of memory. The functions call lower level functions that can be set by the user to give him a full control over memory allocation. So, it is strongly recommended to use these functions. The said above refers only to simple buffers. Temporary images, memory storages and other structures that are created/released using their cvCreate<Object>/cvRelease<Object> should be allocated/deallocated this way (the Create/Release functions call cvAlloc/cvFree internally).
If error occurs and one of the macros CV_ERROR or CV_CALL is used, the control is passed to exit label. The same can be done in the normal program flow by the EXIT macro. The label can be defined either manually or via __BEGIN__ and __END__ macros. The label is introduced for resource deallocation. Memory leaks usually happen when program flow passes though rarely executed branches. One of these cases is connected with using a return statement in one of branches.
The technique, used in the library, helps programmer to avoid most of memory leaks. In the beginning of a function all the pointers are cleared (usually during the initialization). After "exit" label cvFree is called for every pointer. cvFree handles null pointers safely. Inside the function return statement is replaced with EXIT. Thus, we guarantee that memory is deallocated. Of course, we can forget to call cvFree for some blocks, but then leak will happen each time the function executed and thus easy to catch.
Low-level functions in OpenCV are mostly C implementations of primitive operations that present in IPP as well. They differ from previously discussed high-level functions in level of the interface (they take plain pointers and counters, almost no structures) and error processing methodology (they return error code instead of setting global error status). The convenient and safe way to call the function is to use IPPI_CALL macro.
For example function implementation look at cvexample.cpp file.
There is a single string rule in OpenCV about code layout: every file must use consistent formatting style.
Currently used in OpenCV and recommended formatting style looks as follows:
if( a > 5 )
{
int b = a*a;
c = c > b ? c : b + 1;
}
else if( abs(a) < 5 )
{
c--;
}
else
{
printf( "a=%d is far to negative\n", a );
}
Other styles might be also accepted if only the above rule is met. That is, if one changes written by others code, he (she) should use the same coding style.
All the codes must be compliant with the following standards:
- ANSI C � the first C language standard ISO/IEC 9899:1990, modified and corrected in ISO/IEC 9899 COR1: 1994, ISO/IEC 9899 AMD1: 1995 and ISO/IEC 9899 COR2: 1996.
- C9X (newel C standard accepted in 1999) � ISO/IEC 9899.
- C++ standard � ISO/IEC 14882-1998.
One should get rid of compiler-dependent or platform-dependent constructions and system calls, such as:
- compiler pragma's,
- specific keywords, e.g. __stdcall, __inline, __int64(or long long). Use CV_INLINE, CV_STDCALL, int64, respectively, instead.
- compiler extensions, e.g. >? and <? macros for min and max, overloaded macros etc.
- inline assembly
- Unix or Win32-specific calls, e.g. bcopy, readdir, CreateFile, WaitForSingleObject etc.
-
Concrete data sizes instead of sizeof's (sizeof(int) rather than 4), byte order ( *(int*)"\x1\x2\x3\x4" is 0x01020304 or 0x04030201 or what?), simple char instead of signed char or unsigned char for processed data (not for strings). Use short forms uchar for unsigned char and schar for signed char.
Use preprocessor directives for surrounding non-portable pieces of code. Try not to use elements that are standard, but hardly supported by the major compiler vendors.
The documentation for contributed functions is written in HTML, because the format provides text formatting capabilities and hyperlinks, and at the same time it is pretty simple to use and to maintain. Documentation for each function or for group of related functions is placed into separate file, which is referenced from the main page.
Here is an prototype of the main page that contains link to example documentation on the function, implemented in cvexample.cpp
Take a look at these pages and at the corresponding HTML code, containing comments about formatting details. You may make a copy of function documentation HTML, change it appropriately and add a link to it into the index page.
The basic elements of function documentation HTML file include (in that order):
- Page title, which is displayed in a browser title bar and represents an expanded function name or function group name
- A list of keywords. It is used by search engines and miscellaneous utilities for indexing documentation.
- Visible page title, which simply repeats the page title.
- Function name. It matches to the real function name but doesn't include prefix. It should be labelled (using a name HTML tag) to referencing it from other places in the documentation.
- Blurb - a single-line function description.
- Function declaration, surrounded by
<pre> and </pre>, in a form it appears in the header file, except that OPENCVAPI is omitted and usual C++ syntax for default arguments is used instead of CV_DEFAULT macro.
Function parameters description. It is a list of <parameter name, description> pairs.
-
Discussion section that describes what the function does and optionally:
Restrictions on allowed/supported arguments combination
Algorithm references (hyper-link and/or paper title).
Example of use. It is optional (see also the section about writing tests) fragment of code or pseudo-code. Several related functions may share the same example.
A See also section, containing zero or more hyperlinks to the related functions.
-
Each test is implemented as C/C++ function that inputs data from text file and outputs results to another text file. Thus, the function has the following interface:
bool <TestName>( const char* inputfile, const char* output file );
Format of input and output files is not defined. However, if the test system functions are used to read/write high-level data (matrices, filenames, contours etc.) from files, the format of the files should be compatible with the functions.
-
The external or "master" test function executes all or selected tests and compares their output with etalon results, that can be created by other programs or by the same tests in one of the previous executions.
Using this scheme it is possible to implement as tests that check a function on several particular data sets, as well as tests that compare function output with output of etalon function on arbitrary data. In this case output file can be formed as a difference between the two outputs and "etalon results" from the previous paragraph will be all zeros.
-
There is a test system API that makes test implementation easier. This includes:
Test system core (test registration, file management, master test with exception handling capabilities)
Functions for retrieving matrices, filenames and other data from text files and writing data to text files.
checking array for special values
memory management functions that help one to catch memory leaks and buffers boundary violation cases.
random number generation
simple arithmetic functions (matrix operations)
visualization functions
Most of this functionality is implemented as thin layer above OpenCV and HighGUI API.
-
Here is step-by-step description of how to implement test with examples:
-
Create a file with test body:
//
// skeleton_test.cpp
//
#include "opencv_tst.h"
// test function
bool test_skeleton( const char* input, const char* output )
{
// load single image from text file.
IplImage* img = tstLoadImage( input );
// run the function (see cvexample.cpp)
cvRasterSkeleton( img, CV_SKEL_PAVLIDIS );
// save the result
tstSaveImage( output );
}
// register test
OPENCV_REGISTER_TEST( test_skeleton, "cvRasterSkeleton" )
// the above macro is expanded into the following code:
//
// static CvTstReg( test_skeleton, "cvRasterSkeleton",
// "test_skeleton", "skeleton_test.cpp",
// 20 /* code line number */,
// "test_skeleton.in" /* input data file name */
// "test_skeleton.out"/* output data file name */
// "test_skeleton.0" /* etalon data file name */
// );
//
// The line calls constructor of CvTstReg class that links the test to
// the master test list.
-
Add the file to the test system project. File with main() function (which calls master test) is already included into the project, so there is no need to write execution code.
-
Create input data and etalon data. First one probably should be created manually. Etalon data can be produced via dummy pass through tests with -c (--create-etalon) command line flag. Note that, this case can be handled in test functions using tstIsEtalonMode() function (to give possibility to run another variant of algorithm in this case)
The input and output data are stored in opencv_tst/testdata folder. As it might be clear from item #1, names of test data files are formed from the name of test body file and specific extension (".in" for input data, ".out" for current output data and ".0" for etalon data).
That is it. After that the test system may be executed in different modes.
Some of OpenCV functions take small structures on input. Let's name of the structure type be CvSomething. Then cvSomething is usually an inline function, constructing the object from the list of arguments. Use of these inline constructors makes the code easier to write and read.
Use cvRound, cvFloor and cvCeil for fast conversion floating point number to integer with rounding to the nearest, to minus infinity, to plus infinity. On x86 architecture the functions are _much_ faster than simple cast operations. There are standard functions in C9X standard to do the same thing, but they are poorly supported right now. When it happens, the above functions will turn to just one-line macros.
Appendix A. References.
The document is not a complete style guide. Far more detailed and well-written papers on this topic are listed below:
Recommended C Style and Coding Standards (updated version of Indian Hill C Style and Coding Standards). Henry Spencer et al. Rev. 6.0, 1990.
Programming in C++. Rules and Recommendations. Mats Henricson, Erik Nyquist. Ellemtel Communications Systems Laboratories. 1990-1992.
GNU Coding Standards. Richard Stallman. GNU Project � Free Software Foundation. 2000
Notes On Writing Portable Programs in C. A. Dolenc, A. Lemmke, D. Keppel, G.V. Reilly. 1990.
Links to many of these documents can be found at http://www.softpanorama.org/Lang/c.html **.
Appendix B. The brief list of rules
Filenames start with cv prefix and are written in lower case. Headers have .h or .hpp extension. Implementation files have .cpp extension
Every file includes BSD-compatible license in the beginning
Header file have guarding macros and use guarded extern "C"{} for C part of the interface.
Source files include "precomp.h" as the first header.
External function names and data type names are written in mixed case. External macros are written in upper case.
External functions start with cv prefix,
Internal functions - icv,
Data types - Cv,
External macros - CV_.
-
Function declarations have form:
OPENCVAPI <returnType>
<functionName>( arguments );
Function implementations have form:
CV_IMPL <returnType>
<functionName>( arguments )
{
CV_FUNCNAME("<functionName>");
...
__BEGIN__;
...
__END__;
// cleanup ...
return ...;
}
Use CV_ERROR/OPENCV_ERROR to raise an error, CV_CALL/OPENCV_CALL to call high-level function, IPPI_CALL to call lower-level function.
Use cvAlloc and cvFree to allocate temporary buffers.
Keep consistent formatting style in each particular source file.
Be compliant with the C/C++ standards, avoid compiler-dependent, OS- dependent and platform-dependent constructions.
Appendix C. The list of examples and references
contribution license,
function declaration example,
function implementation example
function documentation example
This page was last modified Tuesday, 10-Jul-2001
Back to top
Back to main
|