C++:解除分配 3D 矢量

C++: Deallocating 3d vector

本文关键字:矢量 3D 解除分配 C++      更新时间:2023-10-16

对于 3D 医学图像的 slic 超像素创建,我创建了一个 3d 矢量(std::vector of std::vector of std::vector hold DataStr 对象)。图像尺寸 (~150 x 150 x 150)。DataStr 是一种结构,用于在同一 3D 矢量中存储体素信息,例如指向其邻居的指针矢量。事实证明,使用它比使用邻域迭代器或 KdTree 最近邻搜索循环浏览图像要快得多,因为此信息必须可用于 slic 算法的每次迭代。此外,相比之下,使用它非常方便。但是,当 3d 矢量超出范围时,3d 矢量的释放需要 ~4 分钟。谁能告诉我为什么会这样,我该如何避免这种情况?谢谢!

编辑:

第一次在这里提问,感谢您的耐心等待:-)!

struct DataStr{
  std::vector<DataStr*> neighbors;
  float cmpVal;
  int association;
  cv::Mat index;
  float intensity;
  DataStr() :association{ -1 }, cmpVal{ std::numeric_limits<float>::max() }{}
};

以上是 .hpp 文件中的结构。以下定义和初始化

std::vector<std::vector<std::vector<DataStr>>> dat;
for (int i{ 0 }; i < imgDim[0]; ++i)
{
    dat.resize(imgDim[0]);
    for (int j{ 0 }; j < imgDim[1]; ++j)
    {
        dat[i].resize(imgDim[1]);
        for (int k{ 0 }; k < imgDim[2]; ++k)
        {
            dat[i][j].resize(imgDim[2], DataStr{});
        }
    }
}

imgDim是图像尺寸的3D数组。

 for (it_nImg.GoToBegin(), it_nMask.GoToBegin(), it_nCent.GoToBegin();    !it_nImg.IsAtEnd(); ++it_nImg, ++it_nMask, ++it_nCent)
{       
    auto  idx = it_nMask.GetIndex();
    DataStr* str = &dat[idx[0]][idx[1]][idx[2]];
    (*str).intensity = it_nImg.GetCenterPixel();
    (*str).index = (cv::Mat_<float>(1, 3) << idx[0], idx[1], idx[2]);
    for (int i = 0; i < it_nMask.Size(); ++i)
    {
        auto tmpIdx = it_nMask.GetIndex(i);
        (*str).neighbors.push_back(&dat[tmpIdx[0]][tmpIdx[1]][tmpIdx[2]]);
    }
}
it_n* 是

itk 库中的图像邻域迭代器,用于填充图像中每个体素的 DataStr 中的邻域向量。 it_nMask.Size() 是所选邻域的大小。 it_n*。GetIndex() 提供了 3d 体素索引的 3 元素数组。多谢。

编辑编辑:

如果我存储相邻体素的索引而不是指向它们的指针,则释放只需要 0.5 秒。这是因为指向 DataStr 的指针长度为 8 字节,而 int 在我的机器上只有 4 个字节吗?

您提到性能问题出在析构函数中。 向量向量 向量 向量会导致150 + 150 * 150分配和解除分配。 如果您在分配中没有看到它,我怀疑这是因为它在使用量中摊销了。

在你的情况下可以接受吗

std::vector<DataStr> dat;
int dat_size = imgDim[0] * imgDim[1] * imgDim[2];
dat.reserve(dat_size);
// No need to loop and initialize, the default constructor
// will do that for you.

然后在你的大循环中,替换这一行

DataStr* str = &dat[idx[0]][idx[1]][idx[2]];

有了这个

DataStr& str = dat[dat_index(idx[0], idx[1], idx[2])];

(然后有一些细节,因为我使用了引用而不是指针)。 在这里,我定义了一个辅助函数,

inline int dat_index(int x, int y, int z) {
    return imgDim[0] * imgDim[1] * x + imgDim[0] * y + z;
}

这可能会略有不同,具体取决于您对指数的看法。