EMCV使用说明
emcv是OpenCV针对C6000系列DSP的移植版本,目前只完成了部分功能,如读取图片,轮廓检测。
网上emcv相关资料很少,不少资料也有错误,所以对于开发相当不利,在此记录相关使用方法备查,也希望能帮到后来人。
开发环境:ccs3.3 C6421 Little Endian Simulator TMS320C6400_0(注意emulator与simulator区别,无dsp连接时用simulator可实现大部分功能,且无需下载,比较方便开发调试)
安装方法:
下载Emcv源文件:https://emcv.svn.sourceforge.net/
基于http://www.ti.com/ww/cn/uprogram/share/pdfs/BeagleBoard4.pdf
的方法编译lib并加载至项目。
文档中有以下几点需要说明或更正:
l Emcv已经完成highgui库的移植,虽然部分函数对dsp无意义,但最为重要的loadsave也在这个文件夹下,所以也需要编译与加载highgui目录的内容。
l 加载lib库可以实现功能,但是如果希望断点、分步调试,仍需要将emcv源文件加入include,否则调试中F11进入函数时会提示缺少文件。
l 文档例程载入的是rgb格式的图片。这种格式非常不主流,如需编辑查看图片,可下载ps插件RGBFormat.8BI 也可自己编辑十六进制文件。格式大致如下:前64位文件头+红色通道信息+绿色通道信息+蓝色通道信息 通道信息每两位十六进制数代表一个像素的色深00~ff(0~255) 顺序按照行从下到上,每行从左到右的顺序,即左下是第一个点,右上是最后一点
l 使用view-》graph-》image查看图片需要注意通道选择,interleaved data source选择否,rgb通道分别根据rgb编码规则分别填入相应地址。Image origin选择bottom left
l 加载highgui后无需用load载入,可以用其中的cvLoadImage函数,可以载人bmp格式。使用cvSaveImage可以保存图像,便于调试,而无需使用view-》graph-》image查看
使用说明:
l Emcv尚未开发完全,不少函数仍无法使用。如cvCvtColor,cvCanny等。辨别能否使用,可以先在emcv源文件中查找相应函数名称,如果没有,一定不能使用。如果存在,仍需项目连接时确认其函数实现的代码存在,如果函数没有实现的代码,则会在连接时报错,如cvCanny:
<Linking>
undefined first referenced
symbol in file
--------- ----------------
_cvCanny H:\\dm642\\test\\test3\\Debug\\main.obj
error: unresolved symbols remain
error: errors encountered during linking; "./Debug/test3.out" not built
l 目前测试,与图像检测有关的函数,测试可以使用的有:cvLoadImage,cvCreateImage,cvGetSize,cvThreshold,cvSaveImage,cvCreateMemStorage,cvFindContours,cvInitTreeNodeIterator,cvCreateSeq,cvNextTreeNode,cvStartReadSeq,cvSeqPush,cvPolyLine,cvRectangle
l 存在函数声明但经测试缺少函数实现的有:cvCvtColor,cvCanny,cvBoundingRect,cvminarearect2,cvCircle,cvApproxPoly
l 注意dsp工程需要cmd文件指定存储位置,常见的位置有SRAM和external memory。注意每一存储区域的起始位置和长度限制。如SRAM开始于00000000h 最长00040000h 程序的不同部分(代码,变量,动态分配空间等)需要指定每一section的存储区域,写于cmd文件并需添加入工程。如果位置分配不当,如sysmen分到SRAM则会在运行cvCreateMemStorage()时报错:out of memory。每一位置介绍详见http://wenku.baidu.com/link?url=ov_0JtTkGTWMgSBYev5l2Dr_NWIq0DsUkq7I9rOgYt5fK3F2l4oN7FU8hBeHGYnRH8HdzwhoKy8c9PIWBQmwhqhqu3ZuB07qZn9Cb0M0-f_
错误与修改(如有不当请指正)
Emcv源文件中有部分错误需要注意
l cvCreateMemStorage函数申请的空间后block_size为指定值,但free_space却始终是0,需要人为指定为申请值,否则之后的步骤将显示缺少空间。且free_space不能等于block_size否则seq会分配到全零地址,导致cvSetSeqBlockSize的错误。
l cxdatastructs.cpp:468 怀疑CV_ELEM_SIZE存在错误,使得typesize != elem_size,方便起见,直接改为int typesize =8;
l cvcontours.cpp:635调用cvBoundingRect( contour, 1 );出错,原因可能是cvBoundingRect的函数未写完,由于这一功能并非必须,所以删除该行。
l warning:incompatible redefinition of macro "CV_8TO32F",incompatible redefinition of macro "CV_FAST_CAST_8U” 两个变量出现在不同emcv文件夹下,但删除重复后,文件下内的其他文件会出错,直接忽视即可。
程序效果:
Input:
Output:
代码见附件
/* Example of finding contours in a gray scale image and calculating its center point using EMCV By Chen Li, Kang Feng 2014.8 */ #include <stdio.h> #include <stdlib.h> #include "cv/_cv.h" #include "cxcore/_cxcore.h" #include "highgui/_highgui.h" #include "highgui/highgui.h" int main(int argc,char** argv) { IplImage* img = cvLoadImage("100gray.bmp",CV_LOAD_IMAGE_GRAYSCALE); //cannot link cvtcolor //cvCvtColor(img,img_grey,CV_RGB2GRAY); //so ensure input image is grayscale IplImage* thres_img= cvCreateImage(cvGetSize(img),8,1); cvThreshold(img, thres_img, 128, 255, CV_THRESH_BINARY); cvSaveImage( "out_thres_img.bmp", thres_img); CvMemStorage* storage1 = cvCreateMemStorage((int)sizeof(double)*1000); storage1->free_space=storage1->block_size-(int)sizeof(double); //genrally use canny before finding contour, but can not link cvCanny //cvCanny(img, img, 100, 100 * 2); CvSeq *contours = NULL;//store first contour in the pic //find all contours. count is all contour numbers int count = cvFindContours(thres_img,storage1,&contours,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //use cvApproxPoly to find rough outer contour, but cannot link //contours = cvApproxPoly( contours, sizeof(CvContour), storage1, CV_POLY_APPROX_DP, 3, 1 ); //start fetch and analyse each contour CvTreeNodeIterator iterator; cvInitTreeNodeIterator(&iterator,contours,3); CvSeq* allpointsSeq = cvCreateSeq(CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage1); while( 0 != (contours = (CvSeq*)cvNextTreeNode(&iterator)) ){ int totalx=0; int totaly=0; int onetourlength = contours->total; //total points in a contour CvPoint *points = (CvPoint *)malloc(sizeof(CvPoint) * onetourlength); CvSeqReader reader; CvPoint pt = cvPoint(0,0); cvStartReadSeq(contours,&reader); for(int i = 0 ;i < onetourlength; i++){ CV_READ_SEQ_ELEM(pt,reader); points[i] = pt; cvSeqPush(allpointsSeq,&pt); totalx+=pt.x; totaly+=pt.y; } //draw polygon by points in the contour cvPolyLine(thres_img,&points,&onetourlength,1,0,CV_RGB(255,255,255),1,8,0); //cannot link cvMinAreaRect2 to find the center point or rotate angle of the rectangle contour //CvBox2D rect = cvMinAreaRect2(contours); //mean number of all x and y of contour points is the center point printf("center node:(%d,%d)\n",totalx/onetourlength,totaly/onetourlength); CvPoint centernode1,centernode2; centernode1.x=totalx/onetourlength-1; centernode1.y=totaly/onetourlength-1; centernode2.x=totalx/onetourlength+1; centernode2.y=totaly/onetourlength+1; //draw a 2*2 rectangle to mark the middle point cvRectangle(thres_img,centernode1,centernode2,CV_RGB(255,255,255),1,8,0); } cvSaveImage( "out_final.bmp", thres_img); return 0; }
This article is among the series of FDUROP project. More information: http://104.131.150.53/thinkcmfx/index.php?g=&m=article&a=index&id=17
By:陈力
2014.9.1