移植OpenCV到DM6467的ARM端并集成到C6Accel

 

由于之前将OpenCV封装为codec时程序运行极慢,为了使DSP能够运行OpenCV的一些图像处理算法,现在决定采取三个措施:

1,将OpenCV移植到ARM端,ARM端的程序进行基本的内存分配、重要数据结构的初始化、运行一些非常简单的OpenCV函数,而将一些复杂的OpenCV算法放到DSP端执行。

2,将OpenCV集成到C6Accel中,对于一些C6Accel中已经有的算法就不再用OpenCV实现了,降低了移植复杂度,同时,使用VLIB和IMGLIB中优化过的算法那效率会高很多。

3,考虑到我们开发板上进来的视频流是YUV422SP格式,而OpenCV使用BGR格式,如果进行颜色空间转换,那会占用大量的CPU资源,所以,我们现在就放弃该任务,直接使用灰度图像进行处理,降低了算法的复杂度,进而大大降低的DSP负载。

 

1        移植OpenCV到ARM

1.1  移植OpenCV到ARM的两种方法

移植OpenCV到ARM有两种方法,一是将源码编译成库(可以是动态库或者静态库),二是直接将源码添加进应用程序工程中。

对于第一种方法,我进行了一些尝试,遇到了各种困难,包括编译无法通过、编译通过却无法编译成静态库,编成静态库之后调用又出现问题。后来经过思考,发现OpenCV源码是不能直接编译成库来使用的,必须进行一定修改,于是放弃了第一种方法,转而直接将OpenCV源码添加到应用程序源码中。

1.2  ARM端OpenCV源码修改

在我们的开发板上,ARM上运行Linux操作系统,指针操作时使用的是虚拟地址,而DSP端使用的是物理地址,所以,在Linux上连续的地址在DSP看来其实是不连续的。因此,我们需要修改OpenCV的内存分配函数,使得在Linux中分配的内存是在物理上连续的。这可以通过TI提供的CMEM模块实现。

对于ARM端OpenCV源程序的修改主要就是在cxalloc.c中修改icvAllocDefault函数和icvFreeDefault函数。OpenCV默认的内存分配管理是使用最常见的malloc和free,这在我们的嵌入式系统中是不行的,所以我们该用CMEM提供的内存分配API来替换之。

修改过后的icvAllocDefault和icvFreeDefault函数如下所示:

 

CMEM_AllocParams C6accel_cvCmemParams = {CMEM_HEAP, CMEM_CACHED, 8};

 

static void* icvAllocDefault( size_t size )

{

    static int cvCmemInitCalled = 0;

    if (cvCmemInitCalled == 0)

    {

        CMEM_init();

        cvCmemInitCalled = 1;

    }

   

    uchar* udata = (uchar*)CMEM_alloc(size + sizeof(void*) + CV_MALLOC_ALIGN, &C6accel_cvCmemParams);

    if(!udata)

        return NULL;

    uchar** adata = cvAlignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);

    adata[-1] = udata;

    return adata;

}

 

static int icvFreeDefault(void* ptr)

{

    if(ptr)

    {

        uchar* udata = ((uchar**)ptr)[-1];

        CMEM_free(udata, &C6accel_cvCmemParams);

    }

    return CV_OK;

}

 

在编写内存分配函数时需要注意字节对齐的问题,上面的alloc函数通过一点小技巧实现了分配内存按照32bit对齐,具体实现请研究源码。

 

2        集成OpenCV到C6Accel

2.1  DSP端OpenCV源码修改

对于DSP端我们使用EMCV,由于之前已经修改过EMCV并封装成codec移植到了开发板上正常运行,所以现在可以直接拿来用了。不过现在新添加了一些功能,所以需要从OpenCV 1.0中copy一些代码粘贴进EMCV,这个任务太简单,这里不再详细叙述,请直接参考源码。

2.2  C6Accel修改

这部分的修改和集成VLIB到C6Accel很类似,步骤也差不多,区别就是集成VLIB时使用的是库文件,而现在使用源文件,具体过程包括以下步骤:

1,  将EMCV源文件(包括头文件)添加到~/dsp/alg/src目录下。

2,  添加C6accel_ti_opencvFunctionCall.c到~/dsp/alg/src目录下,该文件是用来根据ID匹配对应OpenCV函数的。

3,  修改~/dsp/alg/project/C6Aceel.pjt文件,扩展工程源文件目录以包含新添加的OpenCV源文件。

4,  修改~/dsp/alg/include/C6Accel.h,包含OpenCV头文件,定义各OpenCV函数的ID。

5,  修改~/dsp/alg/include/iC6Accel_ti.h,添加OpenCV各函数的ID定义,添加各OpenCV函数所需参数的结构体的定义。

6,  修改~/soc/packages/ti/c6accel/iC6Accel_ti.h,定义OpenCV各个函数的ID,定义各个OpenCV函数所需参数的结构体。

7,  在~/soc/c6accelw中添加c6accelw_opencv.c和c6accelw_opencv.h,头文件定义各OpenCV函数的参数,c文件是具体的封装实现。

8,  修改~/soc/c6accelw/c6accelw.c,包含c6accelw_opencv.h该头文件。

3        应用程序编写

3.1  sobel程序修改

这里还是在sobel程序的基础上测试OpenCV的移植效果,对该程序的修改还是集中在video.c文件中,需要在其中添加以下代码:

 

    CvSize size = cvSize(envp->imageWidth, envp->imageHeight); // pal frame, 422, YUV422 semi-planar

    CvPoint point1 = cvPoint(envp->imageWidth / 2 - 50, envp->imageHeight / 2 - 50);

    CvPoint point2 = cvPoint(envp->imageWidth / 2 + 50, envp->imageHeight / 2 + 50); // draw a rectangle in the middle of an image

    CvPoint center = cvPoint(envp->imageWidth / 2, envp->imageHeight / 2);

    CvScalar color = CV_RGB(0, 255, 0); // green

    IplImage *img = NULL;

 

img = cvCreateImage(size, IPL_DEPTH_8U, 1);

 

……

 

        memcpy(img->imageData, Buffer_getUserPtr(hVidBuf), img->imageSize);

        //cvRectangle(img, point1, point2, color, CV_AA, 8, 0);

        C6accel_cvRectangle(hC6, img, point1, point2, color, 1, 8/*CV_AA*/, 0);

        C6accel_cvCircle(hC6, img, center, 50, color, 1, 8 ,0);

      memcpy(Buffer_getUserPtr(hDispBuf), img->imageData, img->imageSize);

 

3.2  编译过程

编译过程和集成VLIB是一样的。

 

cd /opt/ti/dvsdk_3_10_00_19_c6accel_example

make c6accel

make codec

make demos

make install

4        程序运行效果

将程序下载到开发板行运行,串口输出错误提示信息:

 

Encode Decode demo ARM Load: 95% DSP Load: 56% Display Type: D1 PAL Video Codec: H.264 BP Video fps: 13 fps Video bit rate: 0 kbps Video resolution: 720x576 Time: 00:00:09

 

Encode Decode demo ARM Load: 95% DSP Load: 42% Display Type: D1 PAL Video Codec: H.264 BP Video fps: 12 fps Video bit rate: 0 kbps Video resolution: 720x576 Time: 00:00:11

 

Deallocation error

Deallocation error

*** glibc detected *** ./sobel: free(): invalid pointer: 0x42c24490 ***

 

还是内存管理的问题,分配没问题,释放时出问题了。经过多方排查,发现是修改OpenCV 1.0的内存管理函数时修改错了,有两个个地方都多加了一个取地址符&,

 

cvReleaseData函数中:

cvFree( &ptr );

改成:

cvFree( ptr );

 

cvReleaseImageHeader函数中:

cvFree( &img );

改成

cvFree( img );

 

修改之后,程序运行正常。

移植OpenCV到DM6467的ARM端并集成到C6Accel_第1张图片

移植OpenCV到DM6467的ARM端并集成到C6Accel_第2张图片

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