DSP

移植EMCV到DM6467(1)——C++工程测试

2019-07-13 12:19发布


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上的移植取得初步成功。