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

来源:互联网 发布:铁路行业预算软件 编辑:程序博客网 时间:2024/06/05 02:49


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