0%

Windows下编译OpenCV-3.1.0 + 扩展opencv_contrib

  1. 准备
  2. 配置编译生成VS工程文件
    1. 编译器的选择:VS2013 or VS2015?
    2. 第一个错误:FFMpeg下载失败
    3. 第二个错误:ippicv下载失败
  3. 引入opencv_contrib
  4. 使用VS生成dll和lib
    1. 第一个错误:没有生成“object”文件
    2. 可能出现的一个错误:缺少python27_d.lib
  5. 整合dll和lib

准备

使用OpenCV 3.1.0进行图像处理时,需要用到surf、sift等匹配算法,在官网下载的安装包解压得到的工具库中,不包含这些算法库(版权还是别的原因),需要自己编译。如果使用2.x版本,这些算法库包含在nonfree中,在3.0之后的版本中,这些算法库包含在xfeature2d中。

首先下载OpenCV-3.1.0的源代码,官网的下载页面: https://opencv.org/releases/page/4/ ,或者直接点击链接下载: https://github.com/opencv/opencv/archive/3.1.0.zip ,仓库地址:https://github.com/opencv/opencv/releases/tag/3.1.0

image-20200613224750516

然后我们需要下载OpenCV的额外模块(Extra Modules),仓库地址:https://github.com/opencv/opencv_contrib ,opencv_contrib的版本需要适配OpenCV的版本,在release页面(https://github.com/opencv/opencv_contrib/releases?after=3.4.1 )找到3.1.0(https://github.com/opencv/opencv_contrib/releases/tag/3.1.0 ),下载源代码

image-20200613230931992

将下载的两个安装包解压到当前文件夹

image-20200613231301479

配置编译生成VS工程文件

编译器的选择:VS2013 or VS2015?

编译需要用到CMake(下载地址:https://cmake.org/download/ ),同时要求电脑上装有VS或Qt(作为编译器使用)。打开CMake,把opencv-3.1.0里边的CMakeLists.txt拖到CMake中,然后把构建目录的文件夹改为opencv-3.1.0-build,如图:

image-20200613231734871

点击Configure进行编译(提示创建文件夹,选“是”),编译器选择目标IDE(如VS2013、VS2015)。

image-20200613231925721

这影响的是最终生成的dll适配的平台版本,如果选择Visual Studio 12 2013,最终在install文件夹中将会生成vc12下的dll和lib,这个版本对应VS工程的平台工具集(vc12对应v120,vc14对应v140,可以在工程的属性页查看并配置)。

image-20200613232130239

image-20200613232325205

第一个错误:FFMpeg下载失败

解决参考:https://blog.csdn.net/yiyuehuan/article/details/52951574

不出意外的话此时会报错:Error in configuration process, project files may be invalid.

image-20200613232721767

检查错误发现:

image-20200613233023105

错误原因:FFMpeg下载失败,有可能是下载链接失效或者无法访问到远程仓库地址(编译旧版本C++库的时候可能存在类似问题),我们首先定位到第三方库的下载配置处:opencv-3.1.0\3rdparty\ffmpeg,打开ffmpeg.cmake

image-20200613233557849

我们先打开第三方库的远程仓库链接(https://github.com/opencv/opencv_3rdparty ),找到分支master_20150703(https://github.com/opencv/opencv_3rdparty/tree/ffmpeg/master_20150703 ),把需要的三个文件手动下载下来,并且将ffmpeg.cmake中的三条下载命令注释掉

image-20200613233920721

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Binary branch name: ffmpeg/master_20150703
# Binaries were created for OpenCV: e379ea6ed60b0caad4d4e3eea096e9d850cb8c86
set(FFMPEG_BINARIES_COMMIT "8aeefc4efe3215de89d8c7e114ae6f7a6091b8eb")
set(FFMPEG_FILE_HASH_BIN32 "89c783eee1c47bfc733f08334ec2e31c")
set(FFMPEG_FILE_HASH_BIN64 "35fe6ccdda6d7a04e9056b0d73b98e76")
set(FFMPEG_FILE_HASH_CMAKE "8606f947a780071f8fcce8cbf39ceef5")

set(FFMPEG_DOWNLOAD_URL ${OPENCV_FFMPEG_URL};$ENV{OPENCV_FFMPEG_URL};https://raw.githubusercontent.com/Itseez/opencv_3rdparty/${FFMPEG_BINARIES_COMMIT}/ffmpeg/)

# ocv_download(PACKAGE opencv_ffmpeg.dll
# HASH ${FFMPEG_FILE_HASH_BIN32}
# URL ${FFMPEG_DOWNLOAD_URL}
# DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR})

# ocv_download(PACKAGE opencv_ffmpeg_64.dll
# HASH ${FFMPEG_FILE_HASH_BIN64}
# URL ${FFMPEG_DOWNLOAD_URL}
# DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR})

# ocv_download(PACKAGE ffmpeg_version.cmake
# HASH ${FFMPEG_FILE_HASH_CMAKE}
# URL ${FFMPEG_DOWNLOAD_URL}
# DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR})

include(${CMAKE_CURRENT_LIST_DIR}/ffmpeg_version.cmake)

下载完成并注释后,重新打开CMake,点击Configure

第二个错误:ippicv下载失败

第二个错误出现了:

image-20200613234117809

同样的方法,定位到opencv-3.1.0\3rdparty\ippicv,打开downloader.cmake,查看我们需要手动下载的文件。文件中的意思是,当编译的平台为WIN32且不为ARM时,获取包名为ippicv_windows_20151201.zip的文件,包中的子目录名为ippicv_win;ICV的解压目录为/unpack。

image-20200613235211128

来到远程仓库(https://github.com/opencv/opencv_3rdparty/tree/ippicv/master_20151201 ),在这里面发现了我们需要的文件:

image-20200613235057887

我们在downloader.cmake的同级目录下创建文件夹unpack(cmake文件中指定的解压目录),将下载的ippicv_windows_20151201.zip下载到这个文件夹中,然后解压到当前文件夹(根据cmake文件中的语句进行操作),得到如下目录结构:

image-20200614000241805

接着回头把downloader.cmake中的下载语句注释掉,注释后的文件文本内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#
# The script downloads ICV package
#
# On return this will define:
# OPENCV_ICV_PATH - path to unpacked downloaded package
#

function(_icv_downloader)
# Commit SHA in the opencv_3rdparty repo
set(IPPICV_BINARIES_COMMIT "81a676001ca8075ada498583e4166079e5744668")
# Define actual ICV versions
if(APPLE)
set(OPENCV_ICV_PACKAGE_NAME "ippicv_macosx_20151201.tgz")
set(OPENCV_ICV_PACKAGE_HASH "4ff1fde9a7cfdfe7250bfcd8334e0f2f")
set(OPENCV_ICV_PLATFORM "macosx")
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_osx")
elseif(UNIX)
if(ANDROID AND NOT (ANDROID_ABI STREQUAL x86 OR ANDROID_ABI STREQUAL x86_64))
return()
endif()
set(OPENCV_ICV_PACKAGE_NAME "ippicv_linux_20151201.tgz")
set(OPENCV_ICV_PACKAGE_HASH "808b791a6eac9ed78d32a7666804320e")
set(OPENCV_ICV_PLATFORM "linux")
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_lnx")
elseif(WIN32 AND NOT ARM)
set(OPENCV_ICV_PACKAGE_NAME "ippicv_windows_20151201.zip")
set(OPENCV_ICV_PACKAGE_HASH "04e81ce5d0e329c3fbc606ae32cad44d")
set(OPENCV_ICV_PLATFORM "windows")
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_win")
else()
return() # Not supported
endif()

set(OPENCV_ICV_UNPACK_PATH "${CMAKE_CURRENT_LIST_DIR}/unpack")
set(OPENCV_ICV_PATH "${OPENCV_ICV_UNPACK_PATH}${OPENCV_ICV_PACKAGE_SUBDIR}")

# if(DEFINED OPENCV_ICV_PACKAGE_DOWNLOADED
# AND OPENCV_ICV_PACKAGE_DOWNLOADED STREQUAL OPENCV_ICV_PACKAGE_HASH
# AND EXISTS ${OPENCV_ICV_PATH})
# # Package has been downloaded and checked by the previous build
# set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE)
# return()
# else()
# if(EXISTS ${OPENCV_ICV_UNPACK_PATH})
# message(STATUS "ICV: Removing previous unpacked package: ${OPENCV_ICV_UNPACK_PATH}")
# file(REMOVE_RECURSE ${OPENCV_ICV_UNPACK_PATH})
# endif()
# endif()
# unset(OPENCV_ICV_PACKAGE_DOWNLOADED CACHE)

# set(OPENCV_ICV_PACKAGE_ARCHIVE "${CMAKE_CURRENT_LIST_DIR}/downloads/${OPENCV_ICV_PLATFORM}-${OPENCV_ICV_PACKAGE_HASH}/${OPENCV_ICV_PACKAGE_NAME}")
# get_filename_component(OPENCV_ICV_PACKAGE_ARCHIVE_DIR "${OPENCV_ICV_PACKAGE_ARCHIVE}" PATH)
# if(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
# file(MD5 "${OPENCV_ICV_PACKAGE_ARCHIVE}" archive_md5)
# if(NOT archive_md5 STREQUAL OPENCV_ICV_PACKAGE_HASH)
# message(WARNING "ICV: Local copy of ICV package has invalid MD5 hash: ${archive_md5} (expected: ${OPENCV_ICV_PACKAGE_HASH})")
# file(REMOVE "${OPENCV_ICV_PACKAGE_ARCHIVE}")
# file(REMOVE_RECURSE "${OPENCV_ICV_PACKAGE_ARCHIVE_DIR}")
# endif()
# endif()

# if(NOT EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
# if(NOT DEFINED OPENCV_ICV_URL)
# if(DEFINED ENV{OPENCV_ICV_URL})
# set(OPENCV_ICV_URL $ENV{OPENCV_ICV_URL})
# else()
# set(OPENCV_ICV_URL "https://raw.githubusercontent.com/Itseez/opencv_3rdparty/${IPPICV_BINARIES_COMMIT}/ippicv")
# endif()
# endif()

# file(MAKE_DIRECTORY ${OPENCV_ICV_PACKAGE_ARCHIVE_DIR})
# message(STATUS "ICV: Downloading ${OPENCV_ICV_PACKAGE_NAME}...")
# file(DOWNLOAD "${OPENCV_ICV_URL}/${OPENCV_ICV_PACKAGE_NAME}" "${OPENCV_ICV_PACKAGE_ARCHIVE}"
# TIMEOUT 600 STATUS __status
# EXPECTED_MD5 ${OPENCV_ICV_PACKAGE_HASH})
# if(NOT __status EQUAL 0)
# message(FATAL_ERROR "ICV: Failed to download ICV package: ${OPENCV_ICV_PACKAGE_NAME}. Status=${__status}")
# else()
# # Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step
# # on wrong hash
# file(MD5 "${OPENCV_ICV_PACKAGE_ARCHIVE}" archive_md5)
# if(NOT archive_md5 STREQUAL OPENCV_ICV_PACKAGE_HASH)
# message(FATAL_ERROR "ICV: Downloaded copy of ICV package has invalid MD5 hash: ${archive_md5} (expected: ${OPENCV_ICV_PACKAGE_HASH})")
# endif()
# endif()
# endif()

# ocv_assert(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
# ocv_assert(NOT EXISTS "${OPENCV_ICV_UNPACK_PATH}")
# file(MAKE_DIRECTORY ${OPENCV_ICV_UNPACK_PATH})
# ocv_assert(EXISTS "${OPENCV_ICV_UNPACK_PATH}")

# message(STATUS "ICV: Unpacking ${OPENCV_ICV_PACKAGE_NAME} to ${OPENCV_ICV_UNPACK_PATH}...")
# execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz "${OPENCV_ICV_PACKAGE_ARCHIVE}"
# WORKING_DIRECTORY "${OPENCV_ICV_UNPACK_PATH}"
# RESULT_VARIABLE __result)

# if(NOT __result EQUAL 0)
# message(FATAL_ERROR "ICV: Failed to unpack ICV package from ${OPENCV_ICV_PACKAGE_ARCHIVE} to ${OPENCV_ICV_UNPACK_PATH} with error ${__result}")
# endif()

# ocv_assert(EXISTS "${OPENCV_ICV_PATH}")

# set(OPENCV_ICV_PACKAGE_DOWNLOADED "${OPENCV_ICV_PACKAGE_HASH}" CACHE INTERNAL "ICV package hash")

message(STATUS "ICV: Package successfully downloaded")
set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE)
endfunction()

_icv_downloader()

完成后打开CMake,点击Configure,不出意外的话此时不会报错了

引入opencv_contrib

找到变量OPENCV_EXTRA_MODULES_PATH,把opencv_contrib-3.1.0的绝对路径填进去,然后点击Generate,就开始生成了

image-20200614001554567

如果这边opencv_contrib的版本和opencv的版本不一样,可能会产生奇怪的错误。解决的最好办法就是版本适配,否则极有可能瞎折腾。生成结束后,CMake中提示如下:

image-20200614002630708

使用VS生成dll和lib

打开opencv-3.1.0-build,使用VS2013(与编译器对应)打开里边的OpenCV.sln文件,在“生成-批生成”中先把ALL_BUILD的两个勾打上,点击“生成”

image-20200614015333768

待其结束后,勾选INSTALL后的两个勾,进行生成

image-20200614011313362

第一个错误:没有生成“object”文件

错误代码:error C2220

提示信息:error C2220: 警告被视为错误 - 没有生成“object”文件

解决方法:把build文件夹清空,打开CMake重新点击Generate,再进行生成

可能出现的一个错误:缺少python27_d.lib

我进行了两次编译,第一次使用opencv-3.1.0.exe解压的source作为源码进行编译,第二次直接下载opencv-3.1.0.zip的源码进行编译。在第一次编译中,遇到一个问题,生成时提示缺少python27_d.lib文件,报错,后来通过修改工程文件解决了这个问题。但是在直接使用源码编译时,并没有出现这个错误。下面是解决这个错误的方法记录。

错误 24 error LNK1104: 无法打开文件“python27_d.lib”

参考:https://blog.csdn.net/pplxlee/article/details/78067927

在OpenCV项目的bindings中的opencv_python项目中,点击外部依赖项,在其中找到pyconfig.h和object.h文件,修改其中对python27_d.dll的使用

image-20200614034117774

在pyconfig.h中

1
2
3
4
5
#ifdef _DEBUG

# define Py_DEBUG

#endif

修改为:

1
2
3
#ifdef _DEBUG
//# define Py_DEBUG
#endif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* For an MSVC DLL, we can nominate the .lib files used by extensions */
#ifdef MS_COREDLL
# ifndef Py_BUILD_CORE /* not building the core - must be an ext */
# if defined(_MSC_VER)
/* So MSVC users need not specify the .lib file in
their Makefile (other compilers are generally
taken care of by distutils.) */
# ifdef _DEBUG
# pragma comment(lib,"python27_d.lib")
# else
# pragma comment(lib,"python27.lib")
# endif /* _DEBUG */
# endif /* _MSC_VER */
# endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */

修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* For an MSVC DLL, we can nominate the .lib files used by extensions */
#ifdef MS_COREDLL
# ifndef Py_BUILD_CORE /* not building the core - must be an ext */
# if defined(_MSC_VER)
/* So MSVC users need not specify the .lib file in
their Makefile (other compilers are generally
taken care of by distutils.) */
# ifdef _DEBUG
# pragma comment(lib,"python27.lib")
# else
# pragma comment(lib,"python27.lib")
# endif /* _DEBUG */
# endif /* _MSC_VER */
# endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */

在object.h中

1
2
3
4
/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif

修改为

1
2
3
4
/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
//#define Py_TRACE_REFS
#endif

整合dll和lib

生成成功后,在opencv-3.1.0-build目录下生成了一个install文件夹,里边的include和x86文件夹是我们最终需要的东西

image-20200614035035123

首先过河拆桥,把3.1.0文件夹重命名为3.1.0-,然后新建3.1.0的空文件夹,把include和x86拷贝到新的3.1.0文件夹下

image-20200614035846255

接着需要区分一下debug和release版本,打开x86/vc12,把staticlib删掉,把lib重命名为lib-,并新建dll和lib文件夹

image-20200614040107577

首先进入dll,新建两个文件夹:debug和release,把bin文件夹中所有以310d.dll结尾的dll文件全部移动到debug文件夹下,以310.dll结尾的dll文件全部移动到release文件夹下。然后把bin删掉。

接着在新建的lib文件夹中同样创建两个文件夹:debug和release,把lib-中所有以310d.lib结尾的lib文件移动到debug文件夹下,……(操作同dll)。然后删掉lib-文件夹。

这样三件套就集齐了,可以把整个3.1.0-文件夹删掉了。

image-20200614040909636

还蛮占空间的

image-20200614041011136