下载linux版本的arm-compute-library,解压出来即可使用。compute library支持neon和opencl方式,neon方式时利用原生的ARM的neon硬件进行加速。而opencl是一个并行计算框架,同时支持neon硬件和GPU硬件。由于现在使用的ARM的GPU还不支持OpenCL方式,因此就使用预编译库中的linux-armv7a-neon目录中的库文件。编译一个程序的命令如下:
arm-linux-gnueabihf-g++ examples/neon_convolution.cpp utils/Utils.cpp -I. -Iinclude -std=c++11 -mfpu=neon -L. -larm_compute -larm_compute_core -o neon_convolution
在eclipse中进行开发时,只需要像上面命名行一样配置好头文件目录,库文件目录以及库文件即可。
注意
当使用预编译版本的compute library时,在后面使用impott_memory出现段错误问题。所以按照官方法自行编译了neon版本的compute library,将动态库替换后问题得到解决。
在Compute Library中数据都是按照张量的形式存储和使用的。数组为一维张量,图像为二维张量,而像神经网络中使用的卷积核可用三维张量描述。因此在Tensor.h中可以看到如下的一句:
using Image= Tensor;
也就是说Image是Tensor的一个别名而已。
Compute Library在ImageLoader.h中提供了两个图像格式的文件读取类:PPMLoader和JPEGLoader,分别读取PPM和JPEG文件。它们读取图像的操作都很简单,以PPMLoader为列给出读取的代码:
Image img;
PPMLoader ppm;
ppm.open(filename);
ppm.init_image(img, Format::U8); //根据图像文件尺寸和最终使用的图像格式,配置好img
img.allocator()->allocate(); //分配实际的存储空间
if(ppm.is_open())
ppm.fill_image(img); //将图像数据写入到img
JPEGLoader的使用是一样的。注意其中Format必须是U8或者RGB888。但看了一些功能使用的都是U8的格式。所以最好转为U8的格式。
在Utils.h中提供了一个函数用于将图像数据保持到PPM文件:
template <typename T>
void save_to_ppm(T &Tensor, const std::string &ppm_filename);
使用也很简单:
save_to_ppm(img, filename); //img为Image对象
当处理来自摄像头的数据时,可能不需要再分配存储空间,直接使用原有的空间即可。而Image(Tensor)是支持的。代码如下:
Image img;
img.allocator()->init(TensorInfo(640,480, Format::YUYV422)); //这里假设读取到的摄像头数据是YUYV422格式的。
img.allocator()->import_memory((void*)mem); //mem是指向摄像头数据地址的指针
之所以需要将YUYV422转换为RGB888是因为有很多摄像头的输出格式要么为YUYV422,要么为Motion-JPEG。而在图像处理时通常都是使用的RGB格式,因此必须进行格式的转换。
查看https://arm-software.github.io/ComputeLibrary/v19.05/文档,在右边的查找框中输入color可以列出一系列颜色格式转换的函数,其中便可以看到有我们所需要的YUYV到RGB的转换函数colorconvert_yuyv_to_rgb。但最终使用的是NEColorConvert.h中提供的NEColorConvert类提供的功能。
首先,假设摄像头数据存放在buffer_ptr指向的地址,并且已知图像的尺寸和格式为YUYV422,那么可以通过如下代码进行格式转换:
Image src_img, dst_img;
src_img.allocator()->init(TensorInfo(640,480,Format::YUYV422));
src_img.allocator()->import_memory(buffer_ptr); //使用指向原始数据的指针
dst_img.allocator()->init(TensorInfo(640,480,Format::RGB888));
dst_img.allocator()->allocate(); //分配一块空间,存放转换后的图像
NEColorConvert convert;
convert.configure(&src_img, &dst_img);
convert.run; //执行转换
save_to_ppm(dst_img, "test.ppm");