2016-06-09 57 views
2

我想建立使用DLIBface_landmark_detection_ex.cppVisual Studio中一个C++应用。构建应用程序从命令promt运行并且训练有素的模型和图像文件作为参数传递。是否可以在编译时加载/读取shape_predictor_68_face_landmarks.dat?

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以便每次我的应用程序执行它的执行时,它都不会占用更多的内存。

有没有什么办法可以在我的应用程序中打包这个文件,以便它将占用更少的物理内存来运行。

更新:

我怎么能存储此shape_predictor_68_face_landmarks.dat文件中的静态缓冲区,这样每次shape_predictor可以从这个缓冲区中读取。

+1

什么是文件内容?它的结构是什么 –

+0

@HumamHelfawi _shape_predictor_68_face_landmarks.dat_是使用[train_shape_predictor_ex.cpp](http://dlib.net/train_shape_predictor_ex.cpp.html)进行训练后的训练模型。它基本上是二进制文件。 – Mavie

回答

5

是,其可能的,但依赖于Visual Studio和不是跨平台

  1. 你应该创建资源文件,包括hape_predictor_68_face_landmarks.dat到您的项目。详情请参阅https://msdn.microsoft.com/ru-ru/library/7zxb70x7.aspx。这将使编译器从指针把这个文件到你的EXE/DLL

  2. 打开resoure在运行时获取内存指针https://msdn.microsoft.com/en-us/library/windows/desktop/ee719660(v=vs.85).aspx

  3. 创建内存流(的std :: istream的)。

    从该料流与DLIB
  4. 反序列化::反序列化

这里是最小的例子,但没有资源读数:

#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使用开销。如果你需要尽可能小的内存使用量 - 你应该从文件加载

最后一个问题 - 如何通过编译器初始化它。没有现成的解决方案,但可以使用shape_predictor.h/deserialize函数中的代码并手动加载。我想,因为你不会得到较少的内存使用量相比,加载文件,这是坏的解决方案,

所以我的建议是从文件加载一个shape_predictor和全球范围内所有使用它的线程

+1

是否有可能声明此内存membuff ** static **,然后每个新的shape_predictor对象读取/使用此membuff作为可共享资源,并且不会增加创建新对象时的内存消耗。 – Mavie

+0

如何将内存流反序列化为Shape_predictor对象 – Mavie

+0

@VIctor,我改进了我的答案。希望,这会帮助你 – Evgeniy