移植OpenCV到ARM时的注意事项

 

在嵌入式平台中,一般来说是使用C语言进行编程,嵌入式系统所使用的编译器也通常对C语言有更好的优化能力,而对C++语言的支持力度不是很大。OpenCV源码采用C、C++混合编程,所有API既可以用C也可以用C++调用。早期的OpenCV大多使用C语言编写,而OpenCV 1.0之后的版本则主要使用C++了。为了适应嵌入式平台,我们在移植时一般选用早期的OpenCV版本,这里选用的即是OpenCV 1.0。

在移植OpenCV到嵌入式系统中时,有许多需要注意的地方,主要包括两部分:一是内存管理、字节对齐;二是语法问题,主要是指如何修改C++语法和C99版本的C语言语法。具体来说,有以下一些地方需要注意:

(1)内存问题。

我们使用的DM6467是双核架构,ARM+DSP,ARM端运行Linux操作系统,DSP运行DSP/BIOS系统。Linux中对于内存地址使用的是虚拟地址,而DSP没有存储管理器,只能使用物理地址,所以在Linux中分配的连续内存在DSP看来其实是物理上不连续的。因而我们要使用某种方法使得Linux端分配的内存是在物理上连续的,这里使用了CMEM模块来分配连续内存。

要使OpenCV使用CMEM分配连续内存,需要修改OpenCV的内存管理函数cvAlloc()和cvFree_(),这两个函数在cxalloc.cpp文件中,具体的修改办法参见上一周的文档。

(2)C99版C语言语法问题。

C99标准扩展了标准的C语言语法,而OpenCV中部分源码使用了该标准,而我们使用的编译器不支持该标准,所以需要修改响应源码。

在当前的OpenCV中,主要是以下类型代码使用了C99标准:

 

for ( int i = 0; i < 100; i ++ )

{

……

}

 

这里的整形变量i并没有在循环体前面进行声明,这在gnueabi-gcc中无法编译,需要修改为以下代码;

 

int i;

for ( i = 0; i < 100; i ++ )

{

……

}

 

(3)函数形参表。

OpenCV中很多函数在函数声明时设置了默认值,在调用该函数时如果某个参数未设置则使用默认值,如下所示。

 

函数定义:

/* Finds integral image: SUM(X,Y) = sum(x

CVAPI(void) cvIntegral( const CvArr* image, CvArr* sum,

                       CvArr* sqsum CV_DEFAULT(NULL),

                       CvArr* tilted_sum CV_DEFAULT(NULL));

 

函数调用:

cvIntegral( img, sum );

 

我们使用的编译器不支持这种函数原型声明,也不支持这种参数不够的函数调用,对于以上部分代码需要修改为:

 

函数声明改为:

CVAPI(void) cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum, CvArr* tilted_sum);

或者在头文件中添加以下宏定义:

#define CV_DEFAULT(x)

 

函数调用:

cvIntegral( img, sum, NULL, NULL );

 

(4)C++语法问题。

在OpenCV中有很多C++语法的源码,对于这部分代码的修改比较麻烦,必须在理解了代码的基础上才能进行进行修改,否则非常可能改错。在修改时候有两种思路:一是想方设法让代码分支到不包含C++语法的代码段去运行;二是将C++格式的成员变量、方法用C来实现,不过这比较复杂,但有的时候必须这么做。

(5)IPP库和OPENMP。

OpenCV是由Intel发起的,OpenCV中的很多源码都是可以使用Intel处理上优化过的IPP库(以及OPENMP)进行算法加速。OpenCV的代码使得用户在没有安装IPP库时可以使用OpenCV自带的算法来完成运算,在安装了IPP库后可以在编译时自动集成IPP库函数以提高算法运行速度。为了实现用户层的透明,OpenCV中引入了IPPI_CALL()函数,如下所示:

 

        IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,

                         dst->step, dsize, cn, xmin, xmax, xofs, buf ));

 

对于这部分代码的修改比较简单,只需要跟踪源码找到在没有使用IPP库时OpenCV调用的函数是什么,然后替换掉函数名即可,例如上面的函数调用修改之后为:

 

icvResize_Bilinear( src->data.ptr, src->step, ssize, dst->data.ptr, dst->step, dsize, cn, xmax, xofs, yofs, (int *)buf0, (int *)buf1 );

 

(6)宏定义的问题。

在OpenCV中大量使用宏定义,并且很多宏定义代码非常长并且有些语法比较不常见,需要修改,例如以下这个例子:

 

#define  ICV_DEF_RESIZE_BILINEAR_FUNC( flavor, arrtype, worktype, alpha_field,  \

                                       mul_one_macro, descale_macro )           \

static CvStatus CV_STDCALL                                                      \

icvResize_Bilinear_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize,\

                                   arrtype* dst, int dststep, CvSize dsize,     \

                                   int cn, int xmax,                            \

                                   const CvResizeAlpha* xofs,                   \

                                   const CvResizeAlpha* yofs,                   \

                                   worktype* buf0, worktype* buf1 )             \

{                                                                               \

    int prev_sy0 = -1, prev_sy1 = -1;                                           \

    int k, dx, dy;                                                              \

 

修改办法是将其改为函数,如下所示:

 

 

 

static void icvResize_Bilinear( const uchar* src, int srcstep, CvSize ssize,

                                   uchar* dst, int dststep, CvSize dsize,    

                                   int cn, int xmax,                            

                                   const CvResizeAlpha* xofs,                  

                                   const CvResizeAlpha* yofs,                  

                                   int* buf0, int* buf1 ) 

 

 

你可能感兴趣的:(ARM,OpenCV)