読者です 読者をやめる 読者になる 読者になる

空飛ぶ気まぐれ雑記帳

主に趣味とかプログラミングについて扱います。

DLIBのコンパイル For Debugビルド

はじめに

今回ビルドするのは、DLIBというC++で書かれた機械学習用のライブラリです。
dlib C++ Library

どこが問題?

Windows環境にて、VisualStudioを使ってDLIBをDebugビルドでコンパイルしようとすると、幾つかの問題に直面します。
中でも気になるのが以下の3つ。

  1. Windowsでは、DLLの生成ができない(__declspec(dllexport)が定義されていない)。
  2. もし、CMakeLists.txt、add_library内のSTATICをSHAREDに置換するとlibpngのEXPORTマクロのおかげでDLLにはlibpngの内容が書き込まれる。
  3. Debugビルドすると以下のリンクエラーが出る。
_USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_ 

それで、1、2については諦めました……が3は諦めきれないので何とかします。

解決法

まあ、出てくるエラーを読めば書いているのですが。
ENABLE_ASSSERTSマクロをONにしろと、そういうことだそうです。
以下の様なディレクトリ構造でビルドするときのコマンドを一応載せておきます

dlib
|-- dlib-19.0
`-- build
cmake -DDLIB_ENABLE_ASSERS=TRUE ..
cmake --build . --target INSTALL --config=Debug
cmake --build . --target INSTALL --config=Release

番外編

上のコマンドのまんま実行するとDebugとReleaseでlibファイルの名前が同じなので爆死します。
ということでdlib-19.0\CMakeLists.txtと<インストールされたディレクトリ>\lib\cmake\dlibにあるdlib-.cmakeファイルをそれぞれ編集します。

cmake_minimum_required(VERSION 2.8.4)

IF (CMAKE_SIZEOF_VOID_P EQUAL 8) # Architectureの判定 MACだったらもっとスマートにかけるのになあ…
  SET(__INTERNAL_ARCHITECTURE_STRING__ x64)
ELSE()
  SET(__INTERNAL_ARCHITECTURE_STRING__ x86)
ENDIF()

SET(CMAKE_DEBUG_POSTFIX d_${__INTERNAL_ARCHITECTURE_STRING__})
SET(CMAKE_RELEASE_POSTFIX _${__INTERNAL_ARCHITECTURE_STRING__})

add_subdirectory(dlib)
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
  SET(__INTERNAL_ARCHITECTURE_STRING__ x64)
ELSE()
  SET(__INTERNAL_ARCHITECTURE_STRING__ x86)
ENDIF()

# Import target "dlib::dlib" for configuration "Release"
set_property(TARGET dlib::dlib APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(dlib::dlib PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
  IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE "なんか文字列"
  IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/dlib_${__INTERNAL_ARCHITECTURE_STRING__}.lib"
  )

list(APPEND _IMPORT_CHECK_TARGETS dlib::dlib )
list(APPEND _IMPORT_CHECK_FILES_FOR_dlib::dlib "${_IMPORT_PREFIX}/lib/dlib_${__INTERNAL_ARCHITECTURE_STRING__}.lib" )

# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

追記

テストコード貼るの忘れてました。
入力画像からSelectiveSearchで物体っぽい領域を抽出するプログラムです。
本来、閾値処理などで論外な矩形を除外するべきなのですが、それをしていないので、山程矩形が出てきます。
まだ、DLIBの使い方をよく理解していないので、間違っていたらよしなに。

#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/image_transforms.h>

#include <string>

#if defined(_DEBUG) || defined(DEBUG)
#pragma comment(lib, R"(dlibd_x86.lib)")
#else
#pragma comment(lib, R"(dlib_x86.lib)")
#endif

int main(int argc, char** argv)
{
  if(argc < 2)
  {
    std::cerr << "Wrong arguments.\n<Exe name> <Input image>" << std::endl;
    return -1;
  }
  char const* INPUT_FILENAME = argv[1];
  dlib::array2d<dlib::rgb_pixel> image, rect_image;
  dlib::load_image(image, INPUT_FILENAME);
  dlib::assign_image(rect_image, image);  // コピーの方法がわかったので修正しました

  std::vector<dlib::rectangle> rectangles;
  dlib::find_candidate_object_locations(image, rectangles);

  std::cout << rectangles.size() << std::endl;

  for (auto&& rect : rectangles)
  {
    dlib::draw_rectangle(rect_image, rect, dlib::rgb_pixel(255, 0, 0), 1);
  }

  dlib::image_window original_window(image, "Original"), find_rectangles(rect_image, "Result");
  
  original_window.wait_until_closed();
  find_rectangles.wait_until_closed();

  return 0;
}

追記2

番外編で書いてることが微妙に嘘だったんで近日中に修正します。
CMAKE_DEBUG_POSTFIXでライブラリファイルの名前を変えた場合にFindPackageで適切なlibファイルを選択させるためには、dlibConfig.cmakeファイルを編集する必要があります。
具体的には38行目周辺のfind_libraryを以下のようにする必要があります。

IF(WIN32)
  find_library(dlib_DEBUG_X86_LIBRARIES dlibd_x86 HINTS ${dlib_INSTALL_PATH}/lib)
  find_library(dlib_DEBUG_X64_LIBRARIES dlibd_x64 HINTS ${dlib_INSTALL_PATH}/lib)
  find_library(dlib_RELEASE_X86_LIBRARIES dlib_x86 HINTS ${dlib_INSTALL_PATH}/lib)
  find_library(dlib_RELEASE_X64_LIBRARIES dlib_x64 HINTS ${dlib_INSTALL_PATH}/lib)
  IF(CMAKE_SIZEOF_VOIDP EQUAL 8)
    set(dlib_RELEASE_LIBRARIES optimized ${dlib_RELEASE_X64_LIBRARIES})
    set(dlib_DEBUG_LIBRARIES debug ${dlib_DEBUG_X64_LIBRARIES})
  ELSE()
    set(dlib_RELEASE_LIBRARIES optimized ${dlib_RELEASE_X86_LIBRARIES})
    set(dlib_DEBUG_LIBRARIES debug ${dlib_DEBUG_X86_LIBRARIES})
  ENDIF()
  set(dlib_LIBRARIES ${dlib_RELEASE_LIBRARIES} ${dlib_DEBUG_LIBRARIES})
ELSE()
  find_library(dlib_LIBRARIES dlib HINTS ${dlib_INSTALL_PATH}/lib)
ENDIF()