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:OpenCVprojects,则将emcv源码复制到该目录下。由于暂时只使用emcv的cv和cxcore两部分,所以复制时可以只选择这两个文件夹。复制完毕之后,将cv和cxcore目录下所有的.cpp文件全部添加到工程中。然后,将C:CCStudio_v3.3C6000cgtollslib
ts64plus.lib这个库文件添加到工程。
4,修改编译选项。首先需要设置预处理时头文件的搜索路径,也即在compiler命令中添加-i"..emcvcv" -i"..emcvcxcore”。然后,在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 )的代码按如下格式修改(红 {MOD}部分为添加的注释符)。
/*
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
#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
", *(img->imageData), *(img->imageData + 1), *(img->imageData + 2));
cvRectangle(img, point1, point2, color, CV_AA, 0);
printf("%d %d %d
", *(img->imageData), *(img->imageData + 1), *(img->imageData + 2));
cvReleaseImage(&img);
return 0;
}
4 测试结果分析
对于编写的测试程序可以现在VS2010中进行测试,如果运行无误再移植到DSP。
将测试程序添加进工程,编译通过之后下载到开发板运行,最终输出结果如下所示。其中第一行为创建图像的第一个像素点的BGR三个分量值,第二行为将第一个像素点置为绿 {MOD}之后的值,0 -1 0表示的是BGR(0, 255, 0),也即绿 {MOD},表明程序运行无误,EMCV在DSP上的移植取得初步成功。