std::bind 问题 cv::face::FN_FaceDetector
std::bind troubles with cv::face::FN_FaceDetector
我正在写一个 class,它基本上包装了 cv::face::FacemarkLBF OpenCV class,用于面部检测和面部标志检测。
作为这项工作的一部分,我编写了自己的面部检测器函数,它是一个 class 成员,因为它使用的参数可能随时更改。这样做,我未能成功将此成员函数传递给 OpenCV。
当方法 (face_cascade_impl) 是静态的(使用 cv::CascadeClassifier::detectMultiScale 的静态参数)时,一切都很好(编译和运行时)。但是,我现在需要绑定实例成员函数,因为我想使用 class 成员参数。
这是我需要传递给 OpenCV FacemarkLBF 实例的 face_cascade_impl 函数:
bool LBPDetector::face_cascade_impl(cv::InputArray img, cv::OutputArray ROIs, void *data) {
cv::Mat gray;
cv::UMat gray_umat;
std::vector<cv::Rect> faces;
cv::CascadeClassifier *cascade = reinterpret_cast<cv::CascadeClassifier *>(data);
// respect input mat type: separate codepaths for mat/umat
if (img.isUMat()) {
// convert to 8-bit single channel if necessary
if (img.channels() > 1) {
cv::cvtColor(img, gray_umat, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray_umat, gray_umat);
} else {
cv::equalizeHist(img, gray_umat);
}
} else {
if (img.channels() > 1) {
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray, gray);
} else {
cv::equalizeHist(img, gray);
}
}
// detect faces
if (img.isUMat()) {
cascade->detectMultiScale(gray_umat, faces, m_params.cascade_scale_factor,
m_params.cascade_min_neighbours, m_params.cascade_flags,
m_params.cascade_min_size);
} else {
cascade->detectMultiScale(gray, faces, m_params.cascade_scale_factor,
m_params.cascade_min_neighbours, m_params.cascade_flags,
m_params.cascade_min_size);
}
cv::Mat(faces).copyTo(ROIs);
return true;
};
说 cv::face::FacemarkLBF 实例是在我的 LBPDetector 构造函数中创建的:
LBPDetector::LBPDetector() {
m_impl = cv::face::FacemarkLBF::create(m_facemark_params);
m_face_cascade = nullptr;
m_facemark_model_loaded = false;
m_params.cascade_scale_factor = 1.1;
m_params.cascade_min_neighbours = 3;
m_params.cascade_flags = cv::CASCADE_SCALE_IMAGE;
m_params.cascade_min_size = cv::Size(30, 30);
}
现在有另一个成员函数实际初始化该实例并加载人脸级联模型:
bool LBPDetector::load_face_cascade(const std::string &path) {
m_facemark_model_loaded = false;
if (path.empty()) {
return false;
}
m_face_cascade = new cv::CascadeClassifier(path);
m_impl->setFaceDetector(std::bind(&LBPDetector::face_cascade_impl, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3), m_face_cascade);
return true;
}
但是,上面的代码编译失败。
这是 GCC 错误消息:
lbp_detector.cpp:77:29: error: no viable conversion from 'typename _Bind_helper<__is_socketlike<bool (LBPDetector::*)(const _InputArray &, const _OutputArray &, void *)>::value, bool (LBPDetector::*)(const _InputArray &, const _OutputArray &, void *), LBPDetector *, const _Placeholder<1> &, const _Placeholder<2> &, const _Placeholder<3> &>::type' (aka '_Bind<bool (sph::face::LBPDetector::*(sph::face::LBPDetector *, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(const cv::_InputArray &, const cv::_OutputArray &, void *)>') to 'cv::face::FN_FaceDetector' (aka 'bool (*)(const cv::_InputArray &, const cv::_OutputArray &, void *)')
facemark_train.hpp:351:50: note: passing argument to parameter 'detector' here
我的系统是 Fedora 30 和 GCC 9:
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Ziel: x86_64-redhat-linux
Konfiguriert mit: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread-Modell: posix
gcc-Version 9.1.1 20190503 (Red Hat 9.1.1-1) (GCC)
绑定函数有状态,因此不能转换为函数指针。您将需要一个自由函数或静态成员函数。
幸运的是,第三个 void* userData
参数存在。您可以使用它来传递指向对象的指针:
bool LBPDetector::load_face_cascade(const std::string &path) {
//...
m_face_cascade = new cv::CascadeClassifier(path);
m_impl->setFaceDetector(LBPDetector::face_cascade_static, this);
return true;
}
bool LBPDetector::face_cascade_static(cv::InputArray img, cv::OutputArray ROIs, void *data)
{
return reinterpret_cast<LBPDetector*>(data)->face_cascade_impl(img, ROIs);
}
bool LBPDetector::face_cascade_impl(cv::InputArray img, cv::OutputArray ROIs)
{
//...
cv::CascadeClassifier *cascade = m_face_cascade;
//...
}
我正在写一个 class,它基本上包装了 cv::face::FacemarkLBF OpenCV class,用于面部检测和面部标志检测。 作为这项工作的一部分,我编写了自己的面部检测器函数,它是一个 class 成员,因为它使用的参数可能随时更改。这样做,我未能成功将此成员函数传递给 OpenCV。
当方法 (face_cascade_impl) 是静态的(使用 cv::CascadeClassifier::detectMultiScale 的静态参数)时,一切都很好(编译和运行时)。但是,我现在需要绑定实例成员函数,因为我想使用 class 成员参数。
这是我需要传递给 OpenCV FacemarkLBF 实例的 face_cascade_impl 函数:
bool LBPDetector::face_cascade_impl(cv::InputArray img, cv::OutputArray ROIs, void *data) {
cv::Mat gray;
cv::UMat gray_umat;
std::vector<cv::Rect> faces;
cv::CascadeClassifier *cascade = reinterpret_cast<cv::CascadeClassifier *>(data);
// respect input mat type: separate codepaths for mat/umat
if (img.isUMat()) {
// convert to 8-bit single channel if necessary
if (img.channels() > 1) {
cv::cvtColor(img, gray_umat, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray_umat, gray_umat);
} else {
cv::equalizeHist(img, gray_umat);
}
} else {
if (img.channels() > 1) {
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray, gray);
} else {
cv::equalizeHist(img, gray);
}
}
// detect faces
if (img.isUMat()) {
cascade->detectMultiScale(gray_umat, faces, m_params.cascade_scale_factor,
m_params.cascade_min_neighbours, m_params.cascade_flags,
m_params.cascade_min_size);
} else {
cascade->detectMultiScale(gray, faces, m_params.cascade_scale_factor,
m_params.cascade_min_neighbours, m_params.cascade_flags,
m_params.cascade_min_size);
}
cv::Mat(faces).copyTo(ROIs);
return true;
};
说 cv::face::FacemarkLBF 实例是在我的 LBPDetector 构造函数中创建的:
LBPDetector::LBPDetector() {
m_impl = cv::face::FacemarkLBF::create(m_facemark_params);
m_face_cascade = nullptr;
m_facemark_model_loaded = false;
m_params.cascade_scale_factor = 1.1;
m_params.cascade_min_neighbours = 3;
m_params.cascade_flags = cv::CASCADE_SCALE_IMAGE;
m_params.cascade_min_size = cv::Size(30, 30);
}
现在有另一个成员函数实际初始化该实例并加载人脸级联模型:
bool LBPDetector::load_face_cascade(const std::string &path) {
m_facemark_model_loaded = false;
if (path.empty()) {
return false;
}
m_face_cascade = new cv::CascadeClassifier(path);
m_impl->setFaceDetector(std::bind(&LBPDetector::face_cascade_impl, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3), m_face_cascade);
return true;
}
但是,上面的代码编译失败。
这是 GCC 错误消息:
lbp_detector.cpp:77:29: error: no viable conversion from 'typename _Bind_helper<__is_socketlike<bool (LBPDetector::*)(const _InputArray &, const _OutputArray &, void *)>::value, bool (LBPDetector::*)(const _InputArray &, const _OutputArray &, void *), LBPDetector *, const _Placeholder<1> &, const _Placeholder<2> &, const _Placeholder<3> &>::type' (aka '_Bind<bool (sph::face::LBPDetector::*(sph::face::LBPDetector *, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(const cv::_InputArray &, const cv::_OutputArray &, void *)>') to 'cv::face::FN_FaceDetector' (aka 'bool (*)(const cv::_InputArray &, const cv::_OutputArray &, void *)')
facemark_train.hpp:351:50: note: passing argument to parameter 'detector' here
我的系统是 Fedora 30 和 GCC 9:
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Ziel: x86_64-redhat-linux
Konfiguriert mit: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread-Modell: posix
gcc-Version 9.1.1 20190503 (Red Hat 9.1.1-1) (GCC)
绑定函数有状态,因此不能转换为函数指针。您将需要一个自由函数或静态成员函数。
幸运的是,第三个 void* userData
参数存在。您可以使用它来传递指向对象的指针:
bool LBPDetector::load_face_cascade(const std::string &path) {
//...
m_face_cascade = new cv::CascadeClassifier(path);
m_impl->setFaceDetector(LBPDetector::face_cascade_static, this);
return true;
}
bool LBPDetector::face_cascade_static(cv::InputArray img, cv::OutputArray ROIs, void *data)
{
return reinterpret_cast<LBPDetector*>(data)->face_cascade_impl(img, ROIs);
}
bool LBPDetector::face_cascade_impl(cv::InputArray img, cv::OutputArray ROIs)
{
//...
cv::CascadeClassifier *cascade = m_face_cascade;
//...
}