< NCNN-Lession-9 > Load Image
开始
由于马上学习网络forward的部分,这一节先学习一下ncnn如何读取外部图片的.
我们再插一个小红旗:
作用
通常我们读取读片的时候会用到Opencv的Mat类,大家应该发现了,Opencv中的Mat类和ncnn中的Mat类的名字其实是一样的.为了区分方便,我们把Opencv中的Mat类记错cv::Mat,我们把ncnn中的Mat类记做ncnn::Mat.
本节的作用就是用Opencv读取图片,然后把cv::Mat转化为ncnn::Mat.
实现
由于Opencv读一幅彩色图片的格式是bgr的格式,我们今天只考虑bgr的cv::Mat转化到ncnn:Mat.暂时不考虑其他格式的转化.
我们首先考虑一下Opencv::Mat的图片数据存放方式.
Opencv::Mat的索引方式是这样的:
- 先索引列h
- 再索引宽w
- 再索引通道c
可以用下面的表格来看一下Opencv的数据存放方式:
b | g | r | b | g | r | … | pad? |
---|---|---|---|---|---|---|---|
b | g | r | b | g | r | … | pad? |
对上面的表格做一个说明:
元素分布是按照bgrbgrbgr….的顺序排列的.
每一行代表一个行(一个w)数据.
pad?代表是否需要pad操作.Opencv默认内存是连续的,也就是没有pad操作.
上面是用表格的形式展示的,在内存上,上面的所有行是连在一起的.
我们先考虑Opencv内存是连续的情况.
由于我们之前学过,ncnn::Mat中有ncnn::channel的函数,它可以返回一个对应channel的新的ncnn::Mat对象.所以我们可以针对bgr这三个通道各自建立一个channel对象,并每隔3个元素分别读入即可.
1 | static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m, |
现在我们考虑cv::Mat中每一行的内存需要pad,也就是内存不连续的情况.
这个时候我们需要知道Mat的stride,也就是加上pad之后一行有多少个元素.所以pad的个数就是:
1 | const int wgap = stride - w * 3; |
在求得wgap之后,每一行读完之后,指针需要移动wgap的数目.
所以,具体的实现方式如下:
1 | static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m, |
如果我们把上述两种情况都考虑在一起,它的实现方式如下:
1 | static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m, |
代码示例
测试程序在这里.
代码结构如下:
< NCNN-Lession-9 > Load Image