是否可以在编译时 load/read shape_predictor_68_face_landmarks.dat ?
Is it possible to load/read shape_predictor_68_face_landmarks.dat at compile time?
我正在尝试使用 DLIB's face_landmark_detection_ex.cpp 在 Visual Studio 中构建一个 C++ 应用程序。来自命令提示符和经过训练的模型和图像文件的构建应用程序 运行 作为参数传递。
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 file in a static buffer so that every time shape_predictor 可以从这个缓冲区中读取。
是的,有可能,但取决于Visual Studio而不是跨平台
您应该创建资源文件并将 hape_predictor_68_face_landmarks.dat 包含到您的项目中。有关详细信息,请参阅 https://msdn.microsoft.com/ru-ru/library/7zxb70x7.aspx。这将使编译器将此文件放入您的 exe/dll
在运行时打开资源并获取内存指针https://msdn.microsoft.com/en-us/library/windows/desktop/ee719660(v=vs.85).aspx
从指针创建内存流 (std::istream)。
- 使用 dlib::deserialize
从此流反序列化
这是最小的例子,但没有阅读资源:
#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() 是常量,并且文档说对于不同的线程使用一个 shape_predictor 是安全的。
因此,您可以在程序开始时创建一个 shape_predictor 并多次使用它,甚至可以在不同的线程中使用它
接下来,将形状预测器放入资源中将使其在程序启动时加载到 RAM 中,但从资源中反序列化将复制此内存,这将导致 RAM 使用开销。如果您需要尽可能少的 RAM 使用 - 您应该从文件
加载它
最后一个问题 - 如何通过编译器初始化它。没有现成的解决方案,但您可以使用 shape_predictor.h/deserialize 函数中的代码并手动加载它。我认为,这是一个糟糕的解决方案,因为与加载文件相比,您不会获得更少的 RAM 使用量
所以我的建议是从文件中加载一个 shape_predictor 并在所有线程中全局使用它
我知道这是一个老问题,但仅 Visual Studio 的解决方案在我的情况下不起作用,因为我在 Linux/macOS 中使用 dlib
。这是我想出的一个 Unix 兼容的解决方案。
我所做的是使用 xxd 工具将模型文件转换为文件内容的 unsigned char []
表示,将其写入自定义头文件,并在 deserialize
(而不是在执行期间读入文件)。
以下命令将为 shape_predictor_68_face_landmarks.dat
生成头文件:
xxd -i shape_predictor_68_face_landmarks.dat > shape_predictor_68_face_landmarks.hpp
如果您查看 shape_predictor_68_face_landmarks.hpp
,将有 2 个变量:包含模型文件内容的 shape_predictor_68_face_landmarks_dat
类型 unsigned char []
和 shape_predictor_68_face_landmarks_dat_len
类型 [=] 20=].
在您的 dlib
驱动程序代码中,您将执行以下操作
...
#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
生成的文件时要小心,因为它们可能非常大并导致文本编辑器崩溃。
我无法回答这种方法的效率问题,但它确实允许模型文件在编译时 "read in" 而不是执行时。
我正在尝试使用 DLIB's face_landmark_detection_ex.cpp 在 Visual Studio 中构建一个 C++ 应用程序。来自命令提示符和经过训练的模型和图像文件的构建应用程序 运行 作为参数传递。
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 file in a static buffer so that every time shape_predictor 可以从这个缓冲区中读取。
是的,有可能,但取决于Visual Studio而不是跨平台
您应该创建资源文件并将 hape_predictor_68_face_landmarks.dat 包含到您的项目中。有关详细信息,请参阅 https://msdn.microsoft.com/ru-ru/library/7zxb70x7.aspx。这将使编译器将此文件放入您的 exe/dll
在运行时打开资源并获取内存指针https://msdn.microsoft.com/en-us/library/windows/desktop/ee719660(v=vs.85).aspx
从指针创建内存流 (std::istream)。
- 使用 dlib::deserialize 从此流反序列化
这是最小的例子,但没有阅读资源:
#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() 是常量,并且文档说对于不同的线程使用一个 shape_predictor 是安全的。
因此,您可以在程序开始时创建一个 shape_predictor 并多次使用它,甚至可以在不同的线程中使用它
接下来,将形状预测器放入资源中将使其在程序启动时加载到 RAM 中,但从资源中反序列化将复制此内存,这将导致 RAM 使用开销。如果您需要尽可能少的 RAM 使用 - 您应该从文件
加载它最后一个问题 - 如何通过编译器初始化它。没有现成的解决方案,但您可以使用 shape_predictor.h/deserialize 函数中的代码并手动加载它。我认为,这是一个糟糕的解决方案,因为与加载文件相比,您不会获得更少的 RAM 使用量
所以我的建议是从文件中加载一个 shape_predictor 并在所有线程中全局使用它
我知道这是一个老问题,但仅 Visual Studio 的解决方案在我的情况下不起作用,因为我在 Linux/macOS 中使用 dlib
。这是我想出的一个 Unix 兼容的解决方案。
我所做的是使用 xxd 工具将模型文件转换为文件内容的 unsigned char []
表示,将其写入自定义头文件,并在 deserialize
(而不是在执行期间读入文件)。
以下命令将为 shape_predictor_68_face_landmarks.dat
生成头文件:
xxd -i shape_predictor_68_face_landmarks.dat > shape_predictor_68_face_landmarks.hpp
如果您查看 shape_predictor_68_face_landmarks.hpp
,将有 2 个变量:包含模型文件内容的 shape_predictor_68_face_landmarks_dat
类型 unsigned char []
和 shape_predictor_68_face_landmarks_dat_len
类型 [=] 20=].
在您的 dlib
驱动程序代码中,您将执行以下操作
...
#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
生成的文件时要小心,因为它们可能非常大并导致文本编辑器崩溃。
我无法回答这种方法的效率问题,但它确实允许模型文件在编译时 "read in" 而不是执行时。