一、引言
当我们进行前期算法验证的时候,需要读取图片进行仿真,那么关键的一步就是如何加载图片进行测试。需要特别注意的,所有过程都是在HLS工具上实现的,相当于搭建了一个图像的处理平台,不过这个平台的输入源于软件,输出到软件上,后续中间FPGA算法模块的开发,是基于这个图像处理平台的。
方法: 使用openCV的一些函数,cvLoadImage函数加载图片。imread函数读取图片。视频流载入。外部摄像头载入。
Note:新建完工程,除了把源码添加到HLS工具中外,把对应要处理的图片或视频流都放在工程的test bench中。
本实验主要目的,是测试函数的功能,具体函数的使用,后续有机会搞openCV时,会慢慢补充。
二、cvLoadImage
cvLoadImage是openCV里的一个函数,原型:
IplImage* cvLoadImage( const char* filename, int iscolor(CV_LOAD_IMAGE_COLOR) )
1、解释。
filename:指定被读入文件的文件名,需要包含后缀。
flags:指定读入图片的颜色和深度。指定的颜色可将输入的图片转为3信道CV_LOAD_IMAGE_COLOR,单信道CV_LOAD_IMAGE_GRAYSCALE,或者保持不变CV_LOAD_IMAGE_ANYCOLOR。
2、使用。
cvLoadImage( filename, -1 ); // 默认读取图像的原通道数
cvLoadImage( filename, 0 ); // 强制转化读取图像为灰度图
cvLoadImage( filename, 1 ); // 读取彩色图
3、示例。
一个通过 cvLoadImage 函数读取图片显示的例子。
//方法1 cvLoadImage函数加载图片
IplImage* src = cvLoadImage(INPUT_IMAGE); // INPUT_IMAGE是具体的文件明,包含了后缀
IplImage* dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);//获取原始图像大小
AXI_STREAM src_axi, dst_axi;
IplImage2AXIvideo(src, src_axi);
//image_filter(src_axi, dst_axi, src->height, src->width);
AXIvideo2IplImage(src_axi, dst);
cvSaveImage(OUTPUT_IMAGE, dst);
cvShowImage( "test_1080p.bmp",dst);
cvShowImage( "result_1080p",dst);
cvReleaseImage(&src);
cvWaitKey();
4、说明。
IplImage结构体的源码。
typedef struct _IplImage
{
int nSize; /* sizeof(IplImage) */
int ID; /* version (=0)*/
int nChannels; /* Most of OpenCV functions support 1,2,3 or 4 channels */
int alphaChannel; /* Ignored by OpenCV */
int depth; /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,
IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported. */
char colorModel[4]; /* Ignored by OpenCV */
char channelSeq[4]; /* ditto */
int dataOrder; /* 0 - interleaved color channels, 1 - separate color channels.
cvCreateImage can only create interleaved images */
int origin; /* 0 - top-left origin,
1 - bottom-left origin (Windows bitmaps style). */
int align; /* Alignment of image rows (4 or 8).
OpenCV ignores it and uses widthStep instead. */
int width; /* Image width in pixels. */
int height; /* Image height in pixels. */
struct _IplROI *roi; /* Image ROI. If NULL, the whole image is selected. */
struct _IplImage *maskROI; /* Must be NULL. */
void *imageId; /* " " */
struct _IplTileInfo *tileInfo; /* " " */
int imageSize; /* Image data size in bytes
(==image->height*image->widthStep
in case of interleaved data)*/
char *imageData; /* Pointer to aligned image data. */
int widthStep; /* Size of aligned image row in bytes. */
int BorderMode[4]; /* Ignored by OpenCV. */
int BorderConst[4]; /* Ditto. */
char *imageDataOrigin; /* Pointer to very origin of image data
(not necessarily aligned) -
needed for correct deallocation */
}
IplImage;
5、测试。
三、imread
函数原型:CV_EXPORTS_W Mat imread( const string& filename, int flags=1 );
1、解释。
filename:const string&类型,填入文件的路径与文件名,如果文件已经加载到了工程结构中,那直接输入文件名就行。
flags:载入标识,指定一个加载图像的颜色类型。缺省值为1,表示载入3通道的彩色图像。
2、枚举。
flags的变量类型为枚举型,可以查看到具体的值。
enum
{
// 8bit, color or not
IMREAD_UNCHANGED =-1,
// 8bit, gray
IMREAD_GRAYSCALE =0,
// ?, color
IMREAD_COLOR =1,
// any depth, ?
IMREAD_ANYDEPTH =2,
// ?, any color
IMREAD_ANYCOLOR =4
};
3、案例。
通过 imread 函数读取一副图片并且灰度显示。
//方法2 cvLoadImage函数加载图片
Mat src_rgb = imread(INPUT_IMAGE,CV_LOAD_IMAGE_GRAYSCALE);//加载图片并灰度显示
IplImage src = src_rgb;
cvSaveImage(OUTPUT_IMAGE, &src);
cvShowImage("src",&src);
waitKey(0);
return 0;
4、测试。
测试没通过,提示这个错误,目前怀疑是版本的问题,后续可以换2019的hls试试,这个函数就先不用了,毕竟cvLoadImage函数基本也就实现了这个功能。
这个问题可以参考Xilinx官网的这篇文章。
K:\DesktopDocs\imageload\hls_prj\imageload\solution1\csim\build/../../../../../design/Test.cpp:27: undefined reference to `cv::imread(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)'
collect2.exe: error: ld returned 1 exit status
四、视频流载入
主要包括cvCaptureFromAVI函数、cvGrabFrame函数和cvRetrieveFrame函数。
1、cvCaptureFromAVI函数。
cvCaptureFromAVI(“AVI 文件名称”);
1°函数进行视频文件的载入,用来播放AVI文件视频。
2°用 cvCaptureFromAVI()跟 cvCaptureFromFile(),cvCreateFileCapture()都是一样的。
3°文件的类型不一定必须是AVI格式,只要文件符合OpenCV支持的格式就能播放。
2、cvGrabFrame函数。
int cvGrabFrame(CvCapture 结构体);
1°将 capture 抓下來的相片放在 OpenCV 中,与 cvQueryFrame()是相同的步骤。
2°cvGrabFrame()返回值为0或,0是失败,1是成功。
3、cvRetrieveFrame函数。
cvRetrieveFrame(CvCapture 结构);
1°从 OpenCV 快取中得到 Frame,并配置给 IplImage 结构体。
2°cvQueryFrame()=cvGrabFrame()+cvRetrieveFrame()。
//读取视频文件
IplImage *frame;
CvCapture *capture = cvCaptureFromAVI("1.avi");//获取视频数据
cvNamedWindow("AVI player",0);
while(true)
{
if(cvGrabFrame(capture))
{
frame = cvRetrieveFrame(capture);
cvShowImage("AVI player",frame);
if(cvWaitKey(10)>=0) break;
}
else
{
break;
}
}
cvReleaseCapture(&capture);
cvDestroyWindow("AVI player");
return 0;
4、测试。
五、摄像头源
直接上代码,感觉这个不太常用,数据源是笔记本的摄像头。
//摄像头操作
IplImage *frame;
CvCapture *capture = cvCaptureFromCAM(1);//捕获摄像头数据0--笔记本自带摄像头 1--外部摄像头
cvNamedWindow("AVI player",0);
while(true)
{
if(cvGrabFrame(capture))
{
frame = cvRetrieveFrame(capture);
cvShowImage("AVI player",frame);
if(cvWaitKey(10)>=0) break;
}
else
{
break;//没有采集到视频数据退出
}
}
cvReleaseCapture(&capture);
cvDestroyWindow("AVI player");
return 0;
测试。(是的,在实验室的我emmm)
六、时间线
一些关键时间点的记录:
2021年04月20日:测试平台的图片、视频与摄像头读取。
后续可能做的工作:imread函数那个bug的调试(换2019.2版本,据说Xilinx在新版里fix了这个问题)。另外,有机会得对这些函数做些理解(弄到openCV这块时)。