C++ 在文件中读写大型对象

C++ 在文件中读写大型对象,c++,C++,我使用opencv和surf描述符,对于每个图像,我得到一个描述符矩阵, 然后我创建一个大矩阵(Mat)用于法兰索引搜索。 问题是,当大矩阵大小增长(超过30GB)时,我将没有足够的可用内存。 现在我将矩阵序列化为二进制文件,我有一个解决方案:限制最大大小并将其拆分为几个文件,因此每次搜索操作后,我都会按队列读取文件,然后合并结果。 有没有更有效的方法来阅读一次 //代码 class FlannIndexModel { cv::Ptr<cv::flann::Index>

我使用opencv和surf描述符,对于每个图像,我得到一个描述符矩阵, 然后我创建一个大矩阵(Mat)用于法兰索引搜索。 问题是,当大矩阵大小增长(超过30GB)时,我将没有足够的可用内存。 现在我将矩阵序列化为二进制文件,我有一个解决方案:限制最大大小并将其拆分为几个文件,因此每次搜索操作后,我都会按队列读取文件,然后合并结果。 有没有更有效的方法来阅读一次

//代码

   class FlannIndexModel
{
    cv::Ptr<cv::flann::Index> flannIndex;
    cv::Mat dbDescs;
    string fileName;
public:
    vector<IndecesMappingModel> imap;

    FlannIndexModel(string fileName)
    {
        this->fileName = fileName;
        flannIndex = new cv::flann::Index();
    }

    size_t Size()
    {
        size_t sizeInBytes = dbDescs.total() * dbDescs.elemSize();
        return sizeInBytes/1000000;
    }
    void Load()
    {
        FileManager::LoadMat(dbDescs, (fileName + "_desc.bin"));
        FileManager::LoadImap(imap, (fileName + "_imap.bin"));
        flannIndex->load(dbDescs, (fileName + "_flann.bin"));

        cout << " Flann Load: " << " dbDescs rows= " << dbDescs.rows << " imap= " << imap.size() << endl;
    }
    void Save()
    {
        FileManager::SaveMat(dbDescs, (fileName + "_desc.bin"));
        FileManager::SaveImap(imap, (fileName + "_imap.bin"));
        flannIndex->save((fileName + "_flann.bin"));
    }
    void Add(vector<ImageDescModel> imges)
    {
        vector<cv::Mat> descs;

        int r = dbDescs.rows;

        for (int i = 0; i < imges.size(); i++)
        {
            auto desc = imges[i].Desc;
            if (desc.empty())
                continue;
            descs.push_back(desc);
            imap.push_back(IndecesMappingModel(imges[i].FileName, r, r + desc.rows - 1));
            r += desc.rows;
        }
        if (!dbDescs.empty())
            descs.push_back(dbDescs);
        vconcat(descs, dbDescs);
    }
    void Calcul()
    {
        flannIndex->build(dbDescs, cv::flann::KDTreeIndexParams::KDTreeIndexParams(4));
    }


    vector<IndecesMappingModel> Search(cv::Mat queryDescriptors, int num)
    {
        for (auto &img : imap)
        {
            img.Similarity = 0;
        }

        cv::Mat indices(queryDescriptors.rows, 2, CV_32S);
        cv::Mat dists(queryDescriptors.rows, 2, CV_32F);
        flannIndex->knnSearch(queryDescriptors, indices, dists, 2, cv::flann::SearchParams(24));

#pragma omp for
        for (int i = 0; i < indices.rows; i++)
        {
            if (dists.at<float>(i, 0) < (0.6 * dists.at<float>(i, 1)))
            {
                for (auto &img : imap)
                {
                    if (img.IndexStart <= indices.at<int>(i, 0) && img.IndexEnd >= indices.at<int>(i, 0))
                    {
                        img.Similarity++;
                        break;
                    }
                }
            }
        }

        std::sort(imap.begin(), imap.end());

        if (imap.size() > num)
        {
            vector<IndecesMappingModel> result(imap.begin(), imap.begin() + num);
            return result;
        }
        else
        {
            return imap;
        }
    }

};
类法兰索引模型
{
cv::Ptr法兰指数;
cv::Mat dbDescs;
字符串文件名;
公众:
向量imap;
FlannIndexModel(字符串文件名)
{
此->文件名=文件名;
flannIndex=新cv::flann::Index();
}
大小
{
size_t sizeInBytes=dbDescs.total()*dbDescs.elemSize();
返回大小以字节/1000000为单位;
}
空荷载()
{
文件管理器::LoadMat(dbDescs,(fileName+“_desc.bin”);
文件管理器::LoadImap(imap,(文件名+“_imap.bin”);
flannIndex->load(dbDescs,(文件名+“_flann.bin”);

我建议你看看和。我发现
mmap()
技术(第二个链接)非常有趣。你可以在Boost上阅读更多关于这一点的内容。Boost似乎提供了一种执行内存映射文件IO的便携式方法:问题是我需要加载完整的Mat以将其传递给opencv函数。你的意思是我需要映射所有文件(Matrix)吗,然后当我开始搜索时,我会直接从磁盘加载文件?有没有像使用ssd磁盘作为RAM这样的解决方案?不确定“ssd磁盘作为RAM”,您可能想看看这个。关于您之前的评论,我建议您不要拆分矩阵:只需保存整个内容,然后
mmap()
将其指向某个指针,然后将其“包装”在
cv::Mat
中。