在opencv(C++)中从caffe读取多维数组

Posted

技术标签:

【中文标题】在opencv(C++)中从caffe读取多维数组【英文标题】:Read multi-dimensional array from caffe in opencv (C++) 【发布时间】:2018-02-15 17:42:46 【问题描述】:

我在caffe 中有一个模型,它产生一个多维数组。这个数组的大小是[1x10x8x8],所以在python中我对这个大小没有问题,因为python会自动管理这个数组并且我知道其中元素的顺序。但是当我用 c++ 切换到opencv 时,整个数组是一个向量,我不知道如何重新生成类似 python 数组的东西,我使用cv::NAryMatIterator 来访问下面这样的多维数组

const cv::Mat* arrays[]=&prob,0;  //my multi-dimensional array is prob
cv::Mat my_planes[1];
cv::NAryMatIterator it(arrays,my_planes);
cv::Mat Multi_Array ;                               //temporary Mat 
for (int p = 0; p < it.nplanes; ++p,++it) 
    Multi_Array = it.planes[0];

这样做之后,我看到Multi_Array 的大小是[640x1],这似乎等于python 产生的8x8x10。有没有办法一一访问8x8飞机?

编辑:我的多维数组大小是[1x10x8x8]

【问题讨论】:

这些答案是否有助于您解决问题?投票给那些做过的人,然后点击复选框来选择这个问题的最佳答案。通过做这些事情,您正在帮助像您这样的未来访客。 同样的问题,新的一年。 @karlphillip,我完全忘记了这个问题,如果我找到关于 caffe 的文档,我会发布我对这个问题的答案:) 【参考方案1】:

要像访问形状为 [640][1] 的 2D 数组一样访问 3D 数组,您可以编写 3 个循环以使用 [x,y,z] 格式对元素进行迭代,例如:

int data[640][1] =  0 ;
int width = 8, height = 8, depth = 10;

for (int x = 0; x < width; x++)
    for (int y = 0; y < height; y++)
        for (int z = 0; z < depth; z++)
        
            int idx = x * height * depth + y * depth + z;
            data[idx][0] = idx;
        

这会用 0 到 639 之间的数字填充数组。

如果您希望将 2D 数组作为 1D 访问,check this answer。

【讨论】:

【参考方案2】:

如果您的模型数据以行优先格式排序,您可以让 OpenCV 将数据解释为所需大小的 Mat。然后,可以使用multidim_mat.row( row_number ) 访问Mat 的平面。

为了从数据中创建Mat

int data[640] =  0 ;
const int size[] =  8, 8, 10 ;

cv::Mat multidim_mat(3, size, CV_32S, data);

std::cout << multidim_mat.dims << std::endl;
for (int i = 0; i < multidim_mat.dims; i++) 
    std::cout << "Dimension " << i << " is of size " << multidim_mat.size[i] << std::endl;

CV_32S 用于通知 OpenCV 将数据解释为带符号的 32 位整数。

参考:https://docs.opencv.org/3.4.0/d3/d63/classcv_1_1Mat.html#a5fafc033e089143062fd31015b5d0f40、https://docs.opencv.org/3.4.0/d3/d63/classcv_1_1Mat.html#details、

【讨论】:

为什么维数是3? 感谢在我的工作上测试了你的代码后,我意识到我的数据维度是 [1x10x8x8] ,但是我不明白如何访问 opencv 中的一个元素,你能用一个简单的代码来澄清一下吗?! !【参考方案3】:

在第一步中,我们需要获取指向 OpenCV Mat 对象的指针,您可以通过以下命令执行此操作。(我假设表示您的数据的数据主要是 float 并考虑概率 Mat 是 prob,我们从 caffe 获取这个 Mat)

float* p = (float*)(prob.data);

此指针将指向数据驻留在内存中的位置。例如,如果我们想访问 (1,3,7,7) 位置的元素,我们可以这样操作:

int S= sizeof(float);    
float val = p[(
    7*p.step[3]/S +    //forth dimension
    7*p.step[2]/S +    //third dimension
    3*p.step[1]/S      //second dimension
  )]           
 //first dimension is not needed, because it is decoded in address of p
 //and if you have any higher number than 1 in first dimension you need to add it to the above command

所以要遍历概率矩阵,你可以像下面这样:

auto S=sizeof(float);
for (int d2 = 0; d2 < 129; ++d2) 
    for (int d3 = 0; d3 < 129; ++d3) 
        for (int d4 = 0; d4 < 10; ++d4) 
            float val = p[(d2*prob.step[3]/S + d3*prob.step[2]/S + d4* prob.step[1]/S)];
        
    

【讨论】:

以上是关于在opencv(C++)中从caffe读取多维数组的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 中从多维数组创建排列

Opencv C++ 调用 tensorflow 模型caffe模型

使用 C++ 在 OpenCV 中的矩阵中的多维数据

在 OpenCV (C++) 中打印多维 Mat

在执行期间将大型多维数组读取和写入二进制文件并返回数组?

如何在 C++ 中从字节数组(在 BIG-ENDIAN 中)中提取单个字段