这里”C++版本的代码”是指: https://github.com/galian123/cpp_faster_rcnn_detect .
py-faster-rcnn中demo.py代码, 是指 https://github.com/rbgirshick/py-faster-rcnn/blob/master/tools/demo.py 以及
https://github.com/rbgirshick/py-faster-rcnn/tree/master/lib 目录下的一些代码.
涉及到的.py文件都是 https://github.com/rbgirshick/py-faster-rcnn/ 中的.
★ 将图片数据转换成blob
♦ python代码
from utils.blob import im_list_to_blob
def im_detect(net, im, boxes=None):
blobs, im_scales = _get_blobs(im, boxes)
def _get_blobs(im, rois):
blobs['data'], im_scale_factors = _get_image_blob(im)
def _get_image_blob(im):
# Create a blob to hold the input images
# 注意: 在demo.py的处理中, processed_ims中只有一张图片
blob = im_list_to_blob(processed_ims)
return blob, np.array(im_scale_factors)
im_list_to_blob 在 py-faster-rcnn/lib/utils/blob.py
后面有对代码的详细解读.
def im_list_to_blob(ims):
"""Convert a list of images into a network input.
Assumes images are already prepared (means subtracted, BGR order, ...).
"""
# max_shape中的数据是(最大的高,最大的宽,3)
# 由于传入的ims中只有一张图片的信息,所以max_shape的数据就是(图片的高, 宽,3)
max_shape = np.array([im.shape for im in ims]).max(axis=0) # 见"解释1"
num_images = len(ims) # 对于demo.py中的实现来说, 每次只检测一张图片,所以num_images为1
# 创建一个4维数组, 维度为(1, 高, 宽, 3), 类型是float32, 数组中的值都是0
blob = np.zeros((num_images, max_shape[0], max_shape[1], 3),
dtype=np.float32)
for i in xrange(num_images):
im = ims[i]
blob[i, 0:im.shape[0], 0:im.shape[1], :] = im # 见"解释2"
# Move channels (axis 3) to axis 1
# Axis order will become: (batch elem, channel, height, width)
channel_swap = (0, 3, 1, 2)
blob = blob.transpose(channel_swap) # 见"解释3"
return blob
- 解释1: 对
max_shape = np.array([im.shape for im in ims]).max(axis=0)
的解释
举个例子:假设有3个图片,每像素由3通道BGR组成,图片的高宽为100 * 200, 50 * 400, 1000 * 300.
这3个图片的shape为:(100, 200, 3), (50, 400, 3), (1000, 300, 3)
>>> import numpy as np
>>> np.array([(100, 200, 3), (50, 400, 3), (1000, 300, 3)])
array([[ 100, 200, 3],
[ 50, 400, 3],
[1000, 300, 3]])
>>> np.array([(100, 200, 3), (50, 400, 3), (1000, 300, 3)]).max(axis=0)
array([1000, 400, 3]) #取每一列的最大值
>>> np.array([(100, 200, 3), (50, 400, 3), (1000, 300, 3)]).max(axis=1)
array([ 200, 400, 1000]) #取每一行的最大值
max()的参数axis=0表示取每一列中的最大值, axis=1表示取每一行中的最大值.
np.array([im.shape for im in ims]).max(axis=0)
即取出所有图片中(最大的高,最大的宽,3)赋给max_shape.
其实对于demo.py中的实现来说, 每次只处理一张图片.
- 解释2: 将im赋给blob的代码的解释
blob = np.zeros((num_images, max_shape[0], max_shape[1], 3),
dtype=np.float32)
for i in xrange(num_images):
im = ims[i]
blob[i, 0:im.shape[0], 0:im.shape[1], :] = im
将图片im的3维数组装入blob这个4维数组中, 即从多维数组的表达式来看,是在im的外面加上[]
.
由于im.shape[0]和max_shape[0], im.shape[1]和max_shape[1]有可能是不一样的(同时处理多张图片时是不一样的, 但在demo.py的情况中,是一样的.),所以只保留了跟im一样大小的区域中的数据.
blob的最右一个维度的值是3, im最后一个维度的值也是3, 所以在blob中可以用冒号, 表示BGR这3个值都要.
看例子(对冒号的解释):
>>> g = np.array([[1, 1, 1], [2, 2, 2]])
>>> g
array([[1, 1, 1],
[2, 2, 2]])
>>> g.shape
(2, 3)
>>> h = np.zeros((1, g.shape[0], g.shape[1]), dtype=np.float32)
>>> h
array([[[ 0., 0., 0.],
[ 0., 0., 0.]]], dtype=float32)
>>> h[0, 0:g.shape[0], 0:g.shape[1]] = g
>>> h
array([[[ 1., 1., 1.],
[ 2., 2., 2.]]], dtype=float32)
>>> h[0, :, :] = g # 注意: 对于维数相同的, 可以用冒号来代替这一维的所有数据
>>> h
array([[[ 1., 1., 1.],
[ 2., 2., 2.]]], dtype=float32)
- 解释3: 对
blob.transpose
的解释
channel_swap = (0, 3, 1, 2)
blob = blob.transpose(channel_swap)
blob的维度为(1, max_shape[0], max_shape[1], 3), 通过transpose将其维度变换为
(1, 3, max_shapep[0], max_shape[1])
即, 从(1, 高, 宽, 3)变换为(1, 3, 高, 宽), 也就是说, 将下面的形式:
[[[[B,G,R], [B,G,R], ... , [B,G,R]],
[[B,G,R], [B,G,R], ... , [B,G,R]],
...
[[B,G,R], [B,G,R], ... , [B,G,R]]]]
转换成了:
[[[[B, B, B, ..., B],
...
[B, B, B, ..., B]],
[[G, G, G, ..., G],
...
[G, G, G, ..., G]],
[[R, R, R, ..., R],
...
[R, R, R, ..., R]]]]
♦ C++ 代码
float data_buf[height*width*3];
for (int h = 0; h < height; ++h) {
for (int w = 0; w < width; ++w) {
data_buf[(0 * height + h) * width + w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[0]);// Blue
data_buf[(1 * height + h) * width + w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[1]);// Green
data_buf[(2 * height + h) * width + w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[2]);// Red
}
}
从(高,宽,3)变换为(3, 高, 宽), data_buf的内存布局为下图。
B, G, R 每个区域的高度是height, 所以每个区域的起始高度如下:
------------- -> h
| |
| B |
| |
------------- -> height + h
| |
| G |
| |
------------- -> 2 * height + h
| |
| R |
| |
-------------
继续处理im_detect()
中_get_blobs()
之后的代码.
————– 分割线 ————–
本系列文章如下:
- (1) py-faster-rcnn中demo.py代码与C++版本的代码对比: part01 铺垫, demo.py引入的模块
- (2) py-faster-rcnn中demo.py代码与C++版本的代码对比: part02 初始化, 创建Net
- (3) py-faster-rcnn中demo.py代码与C++版本的代码对比: part03 处理图片:减掉平均值, resize
- (4) py-faster-rcnn中demo.py代码与C++版本的代码对比: part04 图片转存为blob
- (5) py-faster-rcnn中demo.py代码与C++版本的代码对比: part05 Reshape
- (6) py-faster-rcnn中demo.py代码与C++版本的代码对比: part06 forward, rois boxes transform
- (7) py-faster-rcnn中demo.py代码与C++版本的代码对比: part07 nms, 获取符合条件的boxes