编译opencv静态库

网上关于编译opencv动态库挺多的,也容易编译,运行例子也没太大问题;到编译opencv静态库问题就挺多,个人通过尝试、成功在linux上编译opencv静态库并调用,并简单做了例子调用,这里简单记录下,可能也不一定准确,请抱着怀疑、验证的态度尝试,个人备忘下。

1. linux上通过cmake编译opencv静态库

cmake需要自己安装,linux上甚至不用特意安装,下载一个可执行的cmake包,配置下环境变量就行,具体编译过程如下:

1. mkdir build
2. cd build && mkdir install
3. cmake … -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_VERBOSE_MAKEFILE=ON -D CMAKE_INSTALL_PREFIX=./install -D BUILD_SHARED_LIBS=OFF -D BUILD_opencv_world=OFF -D BUILD_PNG=ON -D BUILD_JASPER=ON -D BUILD_JPEG=ON -D BUILD_TIFF=ON -D BUILD_ZLIB=ON -D WITH_JPEG=ON -D WITH_PNG=ON -D WITH_JASPER=ON -D WITH_TIFF=ON -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D OPENCV_GENERATE_PKGCONFIG=ON -D BUILD_OPENEXR=ON
4. make -j8
5. sudo make install

这里需要注意, -DBUILD_OPENEXR开启编译第三方库,可以编译出"libIlmImf"这个库,后面静态库会依赖这个库,当初尝试时候卡在这里好久的。

2. linux上简单使用生成的静态库

个人还是用两层CMakeLists.txt来配置测试用例,利用opencv静态库打包新的动态库用到的几个文件:简单调用接口文件"opencvTest1.cpp",“opencvTest1.hpp”;测试用的可执行文件需要的测试代码“”“main.cpp”。:

2.1 外层CMakeLists.txt文件:
project(LINUX_DETECT_SDK)
cmake_minimum_required(VERSION 3.12)


if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")


set(OPCV_DIR  /home/abc/Desktop/soft/APP1/opencv/opencv-4.5.1/build/install)

include_directories(${OPCV_DIR}/include/opencv4) 

link_directories(${OPCV_DIR}/lib) 
link_directories(${OPCV_DIR}/lib/opencv4/3rdparty) 


# Notice the order of dependencies
list(APPEND PROJECT_DEPS libopencv_imgcodecs.a )
list(APPEND PROJECT_DEPS liblibtiff.a )
list(APPEND PROJECT_DEPS liblibjpeg-turbo.a )
list(APPEND PROJECT_DEPS liblibwebp.a )
list(APPEND PROJECT_DEPS libIlmImf.a )
list(APPEND PROJECT_DEPS liblibpng.a )
list(APPEND PROJECT_DEPS liblibopenjp2.a )
list(APPEND PROJECT_DEPS libopencv_imgproc.a )
list(APPEND PROJECT_DEPS libopencv_core.a )
list(APPEND PROJECT_DEPS libippiw.a )
list(APPEND PROJECT_DEPS libippicv.a )
list(APPEND PROJECT_DEPS libittnotify.a )

ADD_SUBDIRECTORY(01_opencv_test)
里面的OPCV_DIR是自己编译opencv后make install后的路径,里面有对应的库和头文件,使用时候要特别注意顺序,上面是自己已经通过target_link_libraries里面添加库并编译库和可执行文件试出来的( -Wl,-ldl,–start-group 库1 库2 -Wl,–end-group 可以自动整理依赖关系);

libopencv_imgcodecs.a 需要 liblibtiff.a, liblibjpeg-turbo.a, liblibwebp.a, libIlmImf.a, liblibpng.a, liblibopenjp2.a libopencv_imgproc.a
libopencv_core.a 需要 libittnotify.a libippiw.a 需要 libippicv.a
libopencv_imgproc.a 需要 libopencv_core.a

2.2 里层CMakeLists.txt文件:
set(MODULE_NAME  opencvTestA)
include_directories(${CMAKE_SOURCE_DIR})

#message(PROJECT_DEPS " ${PROJECT_DEPS}")

# -Wl,-ldl,--start-group liba.a libb.b -Wl,--end-group  #Dependencies can be sorted out automatically
#STATIC SHARED target_link_libraries link_libraries
add_library(${MODULE_NAME} SHARED ${CMAKE_CURRENT_LIST_DIR}/opencvTest1.cpp )

#target_link_libraries(${MODULE_NAME}  libopencv_imgcodecs.a liblibtiff.a liblibjpeg-turbo.a liblibwebp.a libIlmImf.a liblibpng.a liblibopenjp2.a libopencv_imgproc.a libopencv_core.a libippiw.a  libippicv.a  libittnotify.a  z pthread dl)


target_link_libraries(${MODULE_NAME}  ${PROJECT_DEPS}  z pthread dl)

add_executable(test1 ${CMAKE_CURRENT_LIST_DIR}/main.cpp)
target_link_libraries(test1   ${MODULE_NAME} )
注释掉的一个target_link_libraries等同没注释的target_link_libraries部分:

#target_link_libraries(${MODULE_NAME} libopencv_imgcodecs.a liblibtiff.a liblibjpeg-turbo.a liblibwebp.a libIlmImf.a liblibpng.a liblibopenjp2.a libopencv_imgproc.a libopencv_core.a libippiw.a libippicv.a libittnotify.a z pthread dl)

#dl:dlopen dlerror dlclose dlsym等函数的库
#m:math.h中声明的库函数,比如log10等
#pthread:线程建立函数
#z: 不太清楚,也是网上找到的,缺了好像不行

2.3 里层opencvTest1.cpp文件:
#include <iostream>

#include "opencvTest1.hpp"

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

ENCODE_API int opencvTest(const char* imagePath)
{
cv::Mat img2,img3;
img2 = cv::imread(imagePath);
if (img2.empty()) {
    std::cout << " error!  image don't exist!" << std::endl;
    return -2;
}

cv::resize(img2, img3, cv::Size(160, 160), 0,0, INTER_AREA);

cv::imwrite("uvc_out.jpg", img3);

return 0;
}
2.4 里层opencvTest1.hpp文件:
#ifndef _OPENCV_TEST1_
#define _OPENCV_TEST1_

#define ENCODE_API __attribute__((visibility ("default")))

//#ifdef __cplusplus
//extern "C" {
//#endif

extern "C" ENCODE_API int opencvTest(const char* imagePath);

//#ifdef __cplusplus
//}
//#endif
#endif
2.4 里层main.cpp文件:
#include <iostream>
#include "opencvTest1.hpp"

using namespace std;

int main(int argc,const char* argv[])
{
if(argc<1)
{
std::cout<<"error argc is less than 1!!!"<<std::endl;
return -1;
}

const char* imagePath=argv[1];
opencvTest(imagePath);

return 0;
}
例子里面有个好处,对外的接口隐藏了内部的第三方库,如main函数里面就看不到opencv库的相关信息,实际放到服务器上测试,用这一个动态库(试过生成基于静态库的静态库,不成功,基于静态库的动态库是可行的)就够了,当然其它的第三方静态库也可以类似处理。这里没有用class类,如果用class类引出对外的api接口,则可以通过内部类来隐藏第三方库的细节(感谢同事,通过看同事封装一些tflite等库得到一些启发,自己也类似封装了下tflite库,是可行的)。写到这里,自己又要裸辞了,无可奈何,这些年也就学了一点软件,积累了点解决问题的思路,本来再也不想换工作了,害怕也要前行,其实已经拖了好久了,改变是让人不安的,有时却不得不如此,还需要改变提升的太多了,相信自己,少给自己设置限制,多看些好的技术类书籍(里面的内容真是很丰富,好的东西看到就会很喜欢)。