< 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m,
Allocator* allocator) {
m.create(w, h, 3, 4u, allocator);
if (m.empty()) return -100;

float* ptr0 = m.channel(0);
float* ptr1 = m.channel(1);
float* ptr2 = m.channel(2);

int remain = w * h;
for (; remain > 0; remain--) {
*ptr0 = rgb[0];
*ptr1 = rgb[1];
*ptr2 = rgb[2];
rgb += 3;
ptr0++;
ptr1++;
ptr2++;
}

return 0;
}


现在我们考虑cv::Mat中每一行的内存需要pad,也就是内存不连续的情况.

这个时候我们需要知道Mat的stride,也就是加上pad之后一行有多少个元素.所以pad的个数就是:

1
const int wgap = stride - w * 3;

在求得wgap之后,每一行读完之后,指针需要移动wgap的数目.

所以,具体的实现方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m,
Allocator* allocator) {
m.create(w, h, 3, 4u, allocator);
if (m.empty()) return -100;

const int wgap = stride - w * 3;

float* ptr0 = m.channel(0);
float* ptr1 = m.channel(1);
float* ptr2 = m.channel(2);

for (int y = 0; y < h; y++) {
int remain = w;
for (; remain > 0; remain--) {
*ptr0 = rgb[0];
*ptr1 = rgb[1];
*ptr2 = rgb[2];
rgb += 3;
ptr0++;
ptr1++;
ptr2++;
}
rgb += wgap;
}
return 0;
}


如果我们把上述两种情况都考虑在一起,它的实现方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m,
Allocator* allocator) {
m.create(w, h, 3, 4u, allocator);
if (m.empty()) return -100;
const int wgap = stride - w * 3;
if (wgap == 0) {
w = w * h;
h = 1;
}

float* ptr0 = m.channel(0);
float* ptr1 = m.channel(1);
float* ptr2 = m.channel(2);

for (int y = 0; y < h; y++) {
int remain = w;
for (; remain > 0; remain--) {
*ptr0 = rgb[0];
*ptr1 = rgb[1];
*ptr2 = rgb[2];
rgb += 3;
ptr0++;
ptr1++;
ptr2++;
}
rgb += wgap;
}

return 0;
}


代码示例

测试程序在这里

代码结构如下:

Author

Billy

Posted on

2020-12-21

Updated on

2021-03-13

Licensed under

Comments