py-faster-rcnn中demo.py代码与C++版本的代码对比: part04 图片转存为blob

这里”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()之后的代码.

————– 分割线 ————–
本系列文章如下:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值