本系列为darknet源码解析,本次解析src/im2col.h 与 src/im2col.c 两个。这块其实是卷积操作的底层实现。im2col主要是完成矩阵的向量转换,为了之后的gemm.c做矩阵乘法做准备,而im2col和gemm就是darknet卷积底层实现的核心。其实也是caffe卷积实现的核心。
img2col.h 中的包含的代码如下:主要就是一个函数im2col_cpu定义,在这里我们先不涉及gpu那快,先讲解cpu这块的矩阵的向量转换。
#ifndef IM2COL_H
#define IM2COL_H
void im2col_cpu(float* data_im,
int channels, int height, int width,
int ksize, int stride, int pad, float* data_col);
#ifdef GPU
void im2col_gpu(float *im,
int channels, int height, int width,
int ksize, int stride, int pad,float *data_col);
#endif
#endif
im2col.c 的详细分析如下:
#include "im2col.h"
#include <stdio.h>
/**
* 从输入多通道数组im(存储图像数据)中获取指定行、列、通道数处的元素值
* @param im 输入,所有数据都存成一个一维数据,例如对于3通道而言,每一个通道按行存储(每一通道所有行合并成一行)
* 三通道依次再并成一行
* @param height 每一通道的高度(即输入图像的真正高度,补0之前)
* @param width
* @param channels 输入im的通道数,比如彩色图为3通道,之后每一次卷积的输入的通道数等于上一卷积层核的个数
* @param row 要提取的元素所在的行(二维图像补0之后的行数)
* @param col
* @param channel 要提取的元素所在的通道
* @param pad 图像左右上下各补0的长度(四个方向补0的长度一样)
* @return float类型数据,为im中channel通道,row-pad行,col-pad列处的元素值,高,宽;
* 而row与col则是补0之后,元素所在的行列,因此,要准确获取im中元素值,首先要减去pad以获取真实的行列数;
*/
float im2col_get_pixel(float *im, int height, int width, int channels,
int row, int col, int channel, int pad)
{
// 减去补0的长度,得到真实的行数和列数
row -= pad;
col -= pad;
// 如果行列数小于0,则返回0(刚好是补0的效果)
if (row < 0 || col < 0 ||
row >= height || col >= width) return 0;
// im存储多通道二维图像的数据格式为:各通道所有行并后成一行,再多通道一次并成一行;
// 所在指定通道所在行,再加上col移位到所在列
return im[col + width*(row + height*channel)];
}
//From Berkeley Vision's Caffe!
//https://github.com/BVLC/caffe/blob/master