在C ++中优化3D成像过程

时间:2013-05-17 07:12:49

标签: c++ arrays performance vector matrix

我正在使用3D体积图像,可能(256x256x256)。我有3个这样的卷,我想读入并操作。目前,每个卷都存储为我使用ifstream读取的数字文本文件。我将它保存为矩阵(这是我通过动态分配3D数组编写的类)。然后我对这3个矩阵,加法,乘法甚至傅里叶变换执行运算。到目前为止,一切都运行良好,但是,它需要花费很多时间,尤其是傅里叶变换,因为它有6个嵌套循环。

我想知道如何加快速度。此外,我将图像存储在文本文件中的事实是否有所不同。我应该将它们保存为二进制文件还是其他更简单/更快速的格式? fstream是我能读到的最快的方式吗?我每次使用相同的3个矩阵而不更改它们。这有什么区别吗?另外,指向指针的指针是存储3d卷的最佳方式吗?如果不是我还能做什么?

4 个答案:

答案 0 :(得分:4)

  

另外,指向指针的指针是存储3d体积的最佳方式吗?

不是那些通常非常缺乏。

  

如果不能,我还能做什么?

如果将它存储在一个连续的块中,并且在块中使用计算的偏移量,则可能会获得更好的性能。

我通常使用这样的结构:

class DataBlock {

  unsigned int nx;
  unsigned int ny;
  unsigned int nz;
  std::vector<double> data;

  DataBlock(in_nx,in_ny,in_nz) : 
   nx(in_nx), ny(in_ny), nz(in_nz) , data(in_nx*in_ny*in_nz, 0)
  {}

  //You may want to make this check bounds in debug builds
  double& at(unsigned int x, unsigned int y, unsigned int z) { 
    return data[ x + y*nx + z*nx*ny ];
  };

  const double& at(unsigned int x, unsigned int y, unsigned int z) const { 
    return data[ x + y*nx + z*nx*ny ];
  };

  private:
    //Dont want this class copied, so remove the copy constructor and assignment.
    DataBlock(const DataBlock&);
    DataBlock&operator=(const DataBlock&);
};

答案 1 :(得分:3)

将大型(256 ^ 3元素)3D图像文件存储为纯文本是浪费资源。 不失一般性,如果您的图像有明文文件,并且文件的每一行都包含一个值,则必须读取多个字符,直到找到该行的末尾(对于3位数字,这些将是4个字节;数字为3个字节,换行为1个字节)。之后,您必须将这些单个数字转换为数字。使用二进制文件时,您可以直接读取固定数量的字节,然后输入您的数字。 你可以而且应该把它写成二进制图像。

这样做有几种格式,我建议的是VTK的元图像文件格式。在这种格式中,您有一个纯文本头文件和一个包含实际图像数据的二进制文件。使用头文件中的信息,您将知道图像的大小以及将使用的数据类型。在程序中,然后直接读取二进制数据并将其保存到3D数组中。

如果您真的想加快速度,请使用CUDA或OpenCL,这对您的应用来说非常快。

有几个c ++库可以帮助您编写,保存和操作图像数据,包括前面提到的VTK和ITK。

答案 2 :(得分:1)

256 3 是一个相当大的数字。解析256 3 文本字符串将花费相当多的时间。使用二进制文件会使读/写过程更快更多,因为它不需要将数字转换为字符串,也不需要使用更少的空间。例如,要从文本文件中读取数字123为char,程序将需要将其作为字符串读取,并使用大量乘以10从十进制转换为二进制。而如果您将其直接写为二进制文件值0b01111011你只需要将该字节再次读回内存,根本不需要转换。

使用十六进制数也可能会提高读取速度,因为每个十六进制数字可以直接映射到二进制值,但如果您需要更高的速度,二进制文件是可行的方法。只需fread命令即可​​在不到1秒的时间内将整个256 3 bytes = 16MB文件加载到内存中。当你完成后,只需fwrite将其恢复为文件。要加速,您可以使用SIMD(SSE / AVX),CUDA或其他并行处理技术。您可以通过多线程或仅保存非零值来进一步提高速度,因为在许多情况下,大多数值通常为0。

另一个原因可能是因为你的数组很大而且每个维度都是2的幂。这在SO的许多问题中已经讨论过:

您可以考虑将最后一个维度更改为257,然后重试。或者更好地使用其他算法,例如divide and conquer更多cache friendly

答案 3 :(得分:0)

您应该在加载和流程周围添加计时器,以便了解哪个时间占用最多,并将优化工作集中在它上面。如果您控制文件格式,请创建一个更有效的文件格式。如果是处理,我会回应之前的人所说的,研究有效的内存布局以及GPGPU计算。祝你好运。