首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否可以在编译时加载/读取shape_predictor_68_face_landmarks.dat?

是否可以在编译时加载/读取shape_predictor_68_face_landmarks.dat?
EN

Stack Overflow用户
提问于 2016-06-09 11:16:58
回答 2查看 3K关注 0票数 4

我试图在Visual中使用C++应用程序构建德利卜ex.cpp,构建应用程序由命令promt和经过训练的模型和图像文件作为参数传递。

代码语言:javascript
运行
复制
face_landmark_detection_ex.exe shape_predictor_68_face_landmarks.dat image.jpg

shape_predictor_68_face_landmarks.dat是68个地标对输入图像执行检测的训练模型,每次执行任何检测都需要在运行时加载。我正试着做下面的事情。

  • 在构建应用程序或编译时加载此shape_predictor_68_face_landmarks.dat
  • 在代码中阅读这个shape_predictor_68_face_landmarks.dat,这样每当我的应用程序执行它时,它就不会占用更多的内存。

是否有任何方法将此文件打包到我的应用程序中,以减少运行物理内存。

更新:

如何将此landmarks.dat文件存储在静态缓冲区中,以便每次预测器都可以从该缓冲区中读取。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-11 07:31:21

是的,这是可能的,但取决于Visual而不是跨平台。

  1. 您应该创建资源文件并将hape_predictor_68_face_landmarks.dat包含到您的项目中。详情请参见https://msdn.microsoft.com/ru-ru/library/7zxb70x7.aspx。这将使编译器将该文件放入exe/dll中。
  2. 在运行时打开资源并获取内存指针https://msdn.microsoft.com/en-us/library/windows/desktop/ee719660(v=vs.85).aspx
  3. 从指针创建内存流(std::istream)。
代码语言:javascript
运行
复制
1. deserialize from this stream with dlib::deserialize

下面是一个很小的例子,但是没有资源读取:

代码语言:javascript
运行
复制
#include <string>
#include <iostream>
#include <dlib/image_processing/shape_predictor.h>


struct membuf : std::streambuf {
    membuf(char const* base, size_t size) {
        char* p(const_cast<char*>(base));
        this->setg(p, p, p + size);
    }
};
struct imemstream : virtual membuf, std::istream {
    imemstream(char const* base, size_t size)
            : membuf(base, size)
            , std::istream(static_cast<std::streambuf*>(this)) {
    }
};
using namespace dlib; //its important to use namespace dlib for deserialize work correctly
using namespace std;
int main(int argc, const char* argv[])
{
    const char* file_name = "shape_predictor_68_face_landmarks.dat";
    ifstream fs(file_name, ios::binary | ios::ate);
    streamsize size = fs.tellg();
    fs.seekg(0, ios::beg);
    std::vector<char> buffer(size);
    if (fs.read(buffer.data(), size))
    {
        cout << "Successfully read " << size << " bytes from " << file_name << " into buffer" << endl;
        imemstream stream(&buffer.front(), size); // here we are loading from memory buffer. you can change this line to use pointer from Resource
        shape_predictor sp;
        deserialize(sp, stream);
        cout << "Deserialized shape_predictor" << endl;
    }
    else cout << "Failed to read " << file_name << " into buffer" << endl;
    return 0;
}

以及内存的使用。

首先,您应该知道shape_predictor::operator()是const,文档说,对于不同的线程使用一个shape_predictor是安全的。

因此,您可以在程序开始时创建一个shape_predictor,并多次使用它,甚至可以使用不同的线程。

接下来,在资源中放置形状预测器将使它在程序启动时被加载到RAM中,但是从资源反序列化它会复制这个内存,这将导致RAM的使用开销。如果您需要尽可能少地使用RAM -您应该从文件中加载它。

最后一个问题--如何通过编译器初始化它。它没有现成的解决方案,但是您可以使用for _prestor.h/反序列化函数中的代码并手动加载它。我认为,这是一个糟糕的解决方案,因为与加载文件相比,您不会得到更少的内存使用量。

因此,我的建议是从文件中加载一个shape_predictor,并将其全局用于所有线程。

票数 5
EN

Stack Overflow用户

发布于 2019-11-09 22:12:07

我知道这是一个老问题,但是Visual唯一的解决方案在我的情况下是行不通的,因为我在Linux中使用dlib。下面是我想出的一个Unix兼容的解决方案。

我所做的是使用xxd工具将模型文件转换为文件内容的unsigned char []表示,将其写入自定义头文件,并在deserialize中使用它(而不是在执行过程中读取文件)。

下面的命令将生成shape_predictor_68_face_landmarks.dat的头文件

代码语言:javascript
运行
复制
xxd -i shape_predictor_68_face_landmarks.dat > shape_predictor_68_face_landmarks.hpp

如果您查看shape_predictor_68_face_landmarks.hpp内部,将有两个变量:包含模型文件内容的unsigned char []类型的shape_predictor_68_face_landmarks_datunsigned int类型的shape_predictor_68_face_landmarks_dat_len

dlib驱动程序代码中,可以执行以下操作

代码语言:javascript
运行
复制
...
#include "shape_predictor_68_face_landmarks.hpp"
...

shape_predictor sp;
std::stringstream landmarksstream;
landmarksstream.write((const char*)shape_predictor_68_face_landmarks_dat, shape_predictor_68_face_landmarks_dat_len);
deserialize(sp, landmarksstream);

警告词:在打开由xxd 生成的文件时要小心,因为它们可能相当大,导致文本编辑器崩溃。

我不能回答这个方法的效率,但它确实允许在编译时而不是在执行时“读取”模型文件。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37724457

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档