EMCV全称为EmbeddedComputer Vision Library,是一个可在TI DM64x系列DSP上运行的计算机视觉库。EMCV提供了跟OpenCV完全一致的函数接口,通过EMCV,可以轻松地将原有的OpenCV算法移植到DSP,甚至不用改一行代码。
目前EMCV已经支持IplImage,CvMat,CvSeq等基本数据结构,可使用cvCreateImage等创建和释放图像,以及contour检测等。
考虑到OpenCV的复杂性,我们选用EMCV来替代OpenCV在DM6467上进行移植,在移植成功之后,如果需要使用某种图像处理功能,只需要将相关函数从OpenCV源代码中移植到EMCV即可,非常方便。
1 在CCS中新建工程
1,下载EMCV源码。要建立调用EMCV算法的DSP工程,首先需要下载EMCV源码,下载地址为https://emcv.svn.sourceforge.net/svnroot/emcv/,由于源码使用SVN进行管理,所以需要使用SVN工具进行下载,我选用的是TortoiseSVN,依照网络上的教程进行checkout,成功将EMCV源码下载到本地。
2,建立工程。新建TMS320C6++系列DSP的工程,选择out模式。
3,添加源文件。将emcv源码复制到新建工程的同级目录,例如我的DSP路径位于D:\OpenCV\projects,则将emcv源码复制到该目录下。由于暂时只使用emcv的cv和cxcore两部分,所以复制时可以只选择这两个文件夹。复制完毕之后,将cv和cxcore目录下所有的.cpp文件全部添加到工程中。然后,将C:\CCStudio_v3.3\C6000\cgtolls\lib\rts64plus.lib这个库文件添加到工程。
4,修改编译选项。首先需要设置预处理时头文件的搜索路径,也即在compiler命令中添加-i"..\emcv\cv" -i"..\emcv\cxcore”。然后,在linker命令中添加 --no_sym_merge,如果不添加会编译出错。
5,编写cmd文件。接下来需要编写cmd文件分配存储区域,考虑到EMCV函数很占用内存,所以将各个段都放在DDR2上面。另外,需要特别注意stack和heap的大小设置,如果设置得太小,程序在运行时空间不够很可能发生无法预料的结果,所以这里设置stack大小为0x00020000,heap大小为0x00800000,最终的linker.cmd文件如下所示。
-heap 0x00800000 /* Stack Size */ -stack 0x00020000 /* Heap Size */
MEMORY { VECS: o = 0x00000000 l = 0x00000080 IRAM: o = 0x00000080 l = 0x00007f80 /* 32 kBytes */ DRAM: o = 0x00010000 l = 0x00008000 /* 32 kBytes */ /*DDR2: o = 0x80000000 l = 0x10000000*//* 256 MBytes */ DDR2: o = 0x80000000 l = 0x08000000 /* 128 MBytes */ }
SECTIONS { .bss > DDR2 .cinit > DDR2 .cio > DDR2 .const > DDR2 .stack > DDR2 .far > DDR2 .switch > DDR2 .tables > DDR2 .sysmem > DDR2 .text > DDR2 .ddr2 > DDR2 } |
2 修改EMCV源文件
由于EMCV中的源文件是以C++格式编写,很多地方与C不兼容,在CCS中编译时有些代码无法编译通过、或者即使编译通过也无法运行,所以,需要修改EMCV中的一些文件。到现在为止已经修改过的包括以下几处。
1,cxmisc.h第259行
CV_INLINE CvSize cvGetMatSize( const CvMat* mat ) { CvSize size = { mat->width, mat->height }; return size; } |
修改为
CV_INLINE CvSize cvGetMatSize( const CvMat* mat ) { //CvSize size = { mat->width, mat->height }; CvSize size; size.width = mat->cols; size.height = mat->rows; return size; } |
2,cxmisc.h第247行
CV_INLINE void* cvAlignPtr( const void* ptr, int align=32 ) { assert( (align & (align-1)) == 0 ); return (void*)( ((size_t)ptr + align - 1) & ~(size_t)(align-1) ); } |
修改为
CV_INLINE void* cvAlignPtr( const void* ptr, int align CV_DEFAULT(32)) { assert( (align & (align-1)) == 0 ); return (void*)( ((size_t)ptr + align - 1) & ~(size_t)(align-1) ); } |
3,cxtypes.h第211行
CV_INLINE int cvRound( double value ) { if(value >= 0.0) { return int(floor(value + 0.5)); } return int(ceil(value - 0.5)); }
CV_INLINE int cvFloor( double value ) { return int(floor(value)); }
CV_INLINE int cvCeil( double value ) { return int(ceil(value)); } |
修改为
CV_INLINE int cvRound( double value ) { int a; if(value >= 0.0) { //return int(floor(value + 0.5)); a = floor(value + 0.5); return a; } //return int(ceil(value - 0.5)); a = ceil(value - 0.5); return a; }
CV_INLINE int cvFloor( double value ) { //return int(floor(value)); int a = floor(value); return a; }
CV_INLINE int cvCeil( double value ) { //return int(ceil(value)); int a = ceil(value); return a; } |
4,cxarray.cpp
将该文件中所有出现if(!CvIPL.createHeader )的代码按如下格式修改(红色部分为添加的注释符)。
/* if( !CvIPL.createHeader ) { */ CV_CALL( img = (IplImage *)cvAlloc( sizeof( *img ))); CV_CALL( cvInitImageHeader( img, size, depth, channels, IPL_ORIGIN_TL, CV_DEFAULT_IMAGE_ROW_ALIGN )); /* } else { char *colorModel; char *channelSeq;
icvGetColorModel( channels, &colorModel, &channelSeq );
img = CvIPL.createHeader( channels, 0, depth, colorModel, channelSeq, IPL_DATA_ORDER_PIXEL, IPL_ORIGIN_TL, CV_DEFAULT_IMAGE_ROW_ALIGN, size.width, size.height, 0, 0, 0, 0 ); } */ |
到现在为止,修改的地方还很少,因为大部分函数都还没有用到,后面如果想要使用OpenCV的其他功能时很可能还需要大量修改代码。
3 编写测试程序
修改完EMCV源码之后,需要编写测试程序进行测试。这里编写的程序只完成几个很简单的任务:创建图像,在其中添加一个矩形框,释放图像。虽然程序很简单,但是它也包含了一部分OpenCV的基础数据结构,包括CvPoint,CvScalar,CvSize和IplImage,以及几个基本的函数,包括cvCreateImage,cvRectangle和cvReleaseImage。如果这些代码能够运行,那么表明EMCV移植到DSP上的工作初步完成了。最终的程序代码如下所示。
#include <stdio.h> #include "cv.h" int main() { CvPoint point1, point2; point1.x = 0; point1.y = 0; point2.x = 10; point2.y = 10;
CvScalar color = CV_RGB(0, 255, 0);
CvSize size; size.height = 40; size.width = 40;
IplImage* img; img = cvCreateImage(size, IPL_DEPTH_8U, 3); printf("%d %d %d\n", *(img->imageData), *(img->imageData + 1), *(img->imageData + 2)); cvRectangle(img, point1, point2, color, CV_AA, 0); printf("%d %d %d\n", *(img->imageData), *(img->imageData + 1), *(img->imageData + 2));
cvReleaseImage(&img); return 0; } |
4 测试结果分析
对于编写的测试程序可以现在VS2010中进行测试,如果运行无误再移植到DSP。
将测试程序添加进工程,编译通过之后下载到开发板运行,最终输出结果如下所示。其中第一行为创建图像的第一个像素点的BGR三个分量值,第二行为将第一个像素点置为绿色之后的值,0 -1 0表示的是BGR(0, 255, 0),也即绿色,表明程序运行无误,EMCV在DSP上的移植取得初步成功。