# 基于OpenHarmony下的OpenCV库的交叉编译与实施
## 项目概要
#### 开发环境
– 平台:Windows 11、WSL Ubuntu 22.04
– IDE :Deveco Studio 5.0.3.910/6.0 (6.0下没有API12的模拟器)
– SDK:OpenHarmony 5.0.0 API12 FULL-SDK
– 开发模板:Native C++
#### 描述
将OpenCV集成到开发环境,并使用C++实现调用摄像头并进行人脸检测(仅检测人脸位置)
需支持路径加载、Base64格式加载等
## 交叉编译OpenCV
#### 环境准备
– 使用Ubuntu 22.04环境(或使用Windows下的WSL Ubuntu工具)
– ~~~bash
# 更新并获取编译依赖
sudo apt update
sudo apt install build-essential cmake git pkg-config
sudo apt install libgtk-3-dev libavcodec-dev libavformat-dev libswscale-dev
sudo apt install python3-dev python3-numpy
~~~
– ~~~bash
# 获取 opencv源码 版本控制为 4.8.0
git clone https://github.com/opencv/opencv.git
cd opencv
git checkout 4.8.0
~~~
– ~~~bash
# 获取 含有Linux 可用的native 工具的SDK 并解压
wget https://repo.huaweicloud.com/openharmony/os/5.0.0-Release/ohos-sdk-windows_linux-public.tar.gz
mkdir -p OpenHarmony5.0-Linux-SDK
tar -xzf ohos-sdk-windows_linux-public.tar.gz -C OpenHarmony5.0-Linux-SDK –strip-components=1
# 此压缩包为功能拆分压缩的分模块集合 需要二次解压 native
cd ~/OpenHarmony5.0-Linux-SDK
unzip native-linux-x64-5.0.0.71-Release.zip -d native-sdk
~~~
– 现在的文件目录如下
~~~text
~/
├── opencv/
├── OpenHarmony5.0-Linux-SDK
│ └── native-sdk
| └──native
| ├── llvm/ ← Clang 工具链(Linux ELF)
| ├── sysroot/ ← 目标系统头文件和库
| └── build/ ← CMake 工具链文件所在(注意:在 native/ 内!)
| └──…………
└── …
~~~
– ~~~bash
# 1. 检查 clang 是否为 Linux ELF(非 .exe)
file ~/OpenHarmony5.0-Linux-SDK/native-sdk/native/llvm/bin/clang
# 应输出类似:
# …: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), …
# 2. 检查 sysroot
ls ~/OpenHarmony5.0-Linux-SDK/native-sdk/native/sysroot/usr/include/stdio.h
# 3. 检查 CMake 工具链文件
ls ~/OpenHarmony5.0-Linux-SDK/native-sdk/native/build/cmake/ohos.toolchain.cmake
# 如果都存在且 clang 是 ELF 文件,说明 交叉编译环境没有问题
~~~
– 此时,所有的交叉编译工具已经准备完成。
—
#### 开始编译
– 因为默认编译会编译arm64 所以需要建立x86_64的Cmake配置
~~~bash
nano ~/opencv/ohos-x86_64.toolchain.cmake
# ohos-x86_64.toolchain.cmake
set(CMAKE_SYSTEM_NAME OHOS)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
# 指定 OpenHarmony SDK 路径
set(OHOS_SDK_ROOT "$ENV{HOME}/OpenHarmony5.0-Linux-SDK/native-sdk/native")
# 指定编译器
set(CMAKE_C_COMPILER ${OHOS_SDK_ROOT}/llvm/bin/x86_64-unknown-linux-ohos-clang)
set(CMAKE_CXX_COMPILER ${OHOS_SDK_ROOT}/llvm/bin/x86_64-unknown-linux-ohos-clang++)
# 指定 sysroot
set(CMAKE_SYSROOT ${OHOS_SDK_ROOT}/sysroot)
# 必要的编译标志
set(CMAKE_C_FLAGS "–target=x86_64-unknown-linux-ohos –sysroot=${CMAKE_SYSROOT} -D__MUSL__" CACHE STRING "")
set(CMAKE_CXX_FLAGS "–target=x86_64-unknown-linux-ohos –sysroot=${CMAKE_SYSROOT} -D__MUSL__" CACHE STRING "")
# 链接器标志
set(CMAKE_SHARED_LINKER_FLAGS "–rtlib=compiler-rt -fuse-ld=lld -Wl,–no-undefined" CACHE STRING "")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" CACHE STRING "")
# 禁用 rpath
set(CMAKE_SKIP_RPATH TRUE)
~~~
– 然后执行交叉编译 (x86_64)
~~~bash
cd ~/opencv/build-x86
rm -rf *
# 功能根据需要开启 此处禁用了图像处理功能!!
cmake \\
-DCMAKE_TOOLCHAIN_FILE=~/opencv/ohos-x86_64.toolchain.cmake \\
-DCMAKE_INSTALL_PREFIX=~/opencv-ohos-x86_64 \\
-DBUILD_SHARED_LIBS=ON \\
-DBUILD_opencv_apps=OFF \\
-DBUILD_TESTS=OFF \\
-DBUILD_PERF_TESTS=OFF \\
-DBUILD_EXAMPLES=OFF \\
-DWITH_OPENMP=OFF \\
-DWITH_IPP=OFF \\
-DWITH_TBB=OFF \\
-DWITH_EIGEN=OFF \\
-DWITH_V4L=OFF \\
-DWITH_GSTREAMER=OFF \\
-DWITH_FFMPEG=OFF \\
-DWITH_GTK=OFF \\
-DOPENCV_GENERATE_PKGCONFIG=OFF \\
-DWITH_JPEG=OFF \\
-DWITH_PNG=OFF \\
-DWITH_TIFF=OFF \\
-DWITH_WEBP=OFF \\
..
make -j$(nproc)
make install
~~~
– 编译完成后,需要查看生成的动态链接库依赖是否正确(否则会导致仅core导入时正常,导入其他时Napi构建失败)
~~~bash
cd ~/opencv-ohos-x86_64/lib
readelf -d libopencv_core.so | grep NEEDED # 依次查看所有so
# 如果出现[../../lib/libopencv_*.so] 则说明依赖异常
~~~
– 依赖异常时需要进行修复 使用以下代码
~~~bash
# 列出所有 .so 文件
for so in *.so; do
echo "Fixing $so…"
# 将 ../../lib/libxxx.so 替换为 libxxx.so
patchelf –replace-needed ../../lib/libopencv_*.so libopencv_core.so "$so" 2>/dev/null || true
# 可继续添加其他模块…
done
# 修复后重新验证 直到不再出现[../../lib/libopencv_*.so]类似情况
~~~
– 此时,交叉编译已完成,结果保存至
~~~bash
cd opencv-ohos-x86_64
~~~
—
###### 补充
—
**arm32 交叉编译说明**
~~~bash
mkdir -p ~/opencv/build-arm32
cd ~/opencv/build-arm32
rm -rf *
# 创建arm32工具链文件
nano ~/opencv/ohos-arm32.toolchain.cmake
# ohos-arm32.toolchain.cmake
set(CMAKE_SYSTEM_NAME OHOS)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(OHOS_SDK_ROOT "$ENV{HOME}/OpenHarmony5.0-Linux-SDK/native-sdk/native")
set(CMAKE_C_COMPILER ${OHOS_SDK_ROOT}/llvm/bin/armv7-unknown-linux-ohos-clang)
set(CMAKE_CXX_COMPILER ${OHOS_SDK_ROOT}/llvm/bin/armv7-unknown-linux-ohos-clang++)
set(CMAKE_SYSROOT ${OHOS_SDK_ROOT}/sysroot)
set(CMAKE_C_FLAGS "–target=armv7-unknown-linux-ohos –sysroot=${CMAKE_SYSROOT} -D__MUSL__ -march=armv7-a -mfloat-abi=softfp -mfpu=neon" CACHE STRING "")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "")
set(CMAKE_SHARED_LINKER_FLAGS "–rtlib=compiler-rt -fuse-ld=lld -Wl,–no-undefined" CACHE STRING "")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" CACHE STRING "")
set(CMAKE_SKIP_RPATH TRUE)
~~~
然后执行编译
~~~bash
# 功能根据需要开启 此处禁用了图像处理功能!!
cmake \\
-DCMAKE_TOOLCHAIN_FILE=~/opencv/ohos-arm32.toolchain.cmake \\
-DCMAKE_INSTALL_PREFIX=~/opencv-ohos-arm32 \\
-DBUILD_SHARED_LIBS=ON \\
-DBUILD_opencv_apps=OFF \\
-DBUILD_TESTS=OFF \\
-DBUILD_PERF_TESTS=OFF \\
-DBUILD_EXAMPLES=OFF \\
-DWITH_OPENMP=OFF \\
-DWITH_IPP=OFF \\
-DWITH_TBB=OFF \\
-DWITH_EIGEN=OFF \\
-DWITH_V4L=OFF \\
-DWITH_GSTREAMER=OFF \\
-DWITH_FFMPEG=OFF \\
-DWITH_GTK=OFF \\
-DOPENCV_GENERATE_PKGCONFIG=OFF \\
-DWITH_JPEG=OFF \\
-DWITH_PNG=OFF \\
-DWITH_TIFF=OFF \\
-DWITH_WEBP=OFF \\
..
make -j$(nproc)
make install
~~~
—
**arm64 交叉编译说明**
~~~bash
cd ~/opencv/build
rm -rf * # 清理中断产生的残余文件
# 功能根据需要开启 此处禁用了图像处理功能!!
cmake \\
-DCMAKE_TOOLCHAIN_FILE=~/OpenHarmony5.0-Linux-SDK/native-sdk/native/build/cmake/ohos.toolchain.cmake \\
-DPLATFORM=aarch64-linux-ohos \\
-DCMAKE_INSTALL_PREFIX=~/opencv-ohos-arm64 \\
-DBUILD_SHARED_LIBS=ON \\
-DBUILD_opencv_apps=OFF \\
-DBUILD_TESTS=OFF \\
-DBUILD_PERF_TESTS=OFF \\
-DBUILD_EXAMPLES=OFF \\
-DWITH_OPENMP=OFF \\
-DWITH_IPP=OFF \\
-DWITH_TBB=OFF \\
-DWITH_EIGEN=OFF \\
-DWITH_V4L=OFF \\
-DWITH_GSTREAMER=OFF \\
-DWITH_FFMPEG=OFF \\
-DWITH_GTK=OFF \\
-DOPENCV_GENERATE_PKGCONFIG=OFF \\
-DWITH_JPEG=OFF \\
-DWITH_PNG=OFF \\
-DWITH_TIFF=OFF \\
-DWITH_WEBP=OFF \\
..
~~~
## 集成到开发环境
#### 前提
目前已有文件夹 opencv-ohos-x86_64 结构如下
~~~text
.
├── LICENSE
├── bin
│ └── setup_vars_opencv4.sh
├── include
│ └── opencv4
├── lib
│ ├── cmake
│ ├── libopencv_calib3d.so
│ ├── libopencv_core.so
│ ├── libopencv_dnn.so
│ ├── libopencv_features2d.so
│ ├── libopencv_flann.so
│ ├── libopencv_gapi.so
│ ├── libopencv_highgui.so
│ ├── libopencv_imgcodecs.so
│ ├── libopencv_imgproc.so
│ ├── libopencv_ml.so
│ ├── libopencv_objdetect.so
│ ├── libopencv_photo.so
│ ├── libopencv_stitching.so
│ ├── libopencv_video.so
│ └── libopencv_videoio.so
├── out.txt
└── share
├── licenses
└── opencv4
~~~
#### 开始集成
– 在 windows 下 打开 Deveco Studio,新建Native C++ 项目 选择API 为12 在设置将 OpenHarmony SDK 设置为 OpenHarmony 5.0.0 API12 FULL-SDK (假设叫Demo)
– 在 Demo/entry/src/main/cpp 下 新建 opencvLib/x86_64 文件夹 将 opencv-ohos-x86_64 中的lib和include文件夹复制进去 (其他架构同理)
– 打开 Demo/entry/build-profile.json5 修改下面的片段
~~~json
{
"apiType": "stageMode",
"buildOption": {
"externalNativeOptions": {
"abiFilters": ["x86_64","arm64-v8a"], //添加这一行
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
}
},
……
}
~~~
– 打开 Demo/entry/src/main/cpp/napi_init.cpp 上方引入
~~~C++
#include <opencv2/opencv.hpp>
~~~
– 打开 Demo/entry/src/main/cpp/CMakeLists.txt 将里面的内容替换为以下内容
~~~cmake
cmake_minimum_required(VERSION 3.5.0)
project(ceui)
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
# ==============================
# Step 1: Check OHOS_ARCH
# ==============================
if(NOT DEFINED OHOS_ARCH OR "${OHOS_ARCH}" STREQUAL "")
message("OHOS_ARCH is not defined! Please specify with -DOHOS_ARCH=<arch> (e.g., x86_64, arm64-v8a)")
else()
message("Using architecture: ${OHOS_ARCH}")
endif()
# ==============================
# Step 2: Set OpenCV paths (keep your structure)
# ==============================
set(OPENCV_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/libs/opencvLib/${OHOS_ARCH})
message("Checking OpenCV root: ${OPENCV_ROOT}")
if(NOT EXISTS ${OPENCV_ROOT})
message("ERROR: OpenCV root directory does not exist: ${OPENCV_ROOT}")
else()
message("OpenCV root found: ${OPENCV_ROOT}")
endif()
set(OPENCV_INCLUDE_DIR ${OPENCV_ROOT}/include/opencv4)
message("Checking OpenCV headers: ${OPENCV_INCLUDE_DIR}")
if(NOT EXISTS ${OPENCV_INCLUDE_DIR})
message("ERROR: OpenCV include directory missing: ${OPENCV_INCLUDE_DIR}")
else()
message("OpenCV headers found: ${OPENCV_INCLUDE_DIR}")
endif()
set(OPENCV_LIB_DIR ${OPENCV_ROOT}/lib)
message("Checking OpenCV lib dir: ${OPENCV_LIB_DIR}")
if(NOT EXISTS ${OPENCV_LIB_DIR})
message("ERROR: OpenCV lib directory missing: ${OPENCV_LIB_DIR}")
else()
message("OpenCV lib dir found: ${OPENCV_LIB_DIR}")
endif()
# ==============================
# Step 3: Base64 headers (optional)
# ==============================
set(Base64_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/tool)
if(EXISTS ${Base64_INCLUDE_DIR})
message("Base64 headers: ${Base64_INCLUDE_DIR}")
else()
message("⚠ Base64 include dir not found (optional): ${Base64_INCLUDE_DIR}")
endif()
# ==============================
# Step 4: Include directories
# ==============================
include_directories(${OPENCV_INCLUDE_DIR})
include_directories(${Base64_INCLUDE_DIR})
message("Header search paths configured")
# ==============================
# Step 5: Define OpenCV modules
# ==============================
set(OPENCV_MODULES
opencv_core
opencv_imgproc
opencv_calib3d
opencv_dnn
opencv_features2d
opencv_flann
opencv_gapi
opencv_highgui
opencv_imgcodecs
opencv_ml
opencv_objdetect
opencv_photo
opencv_stitching
opencv_video
opencv_videoio
)
message("OpenCV modules to link: ${OPENCV_MODULES}")
# ==============================
# Step 6: Create main library
# ==============================
add_library(entry SHARED napi_init.cpp)
message("Main library 'entry' created")
# ==============================
# Step 7: Prepare build output directory
# ==============================
message("CMAKE_LIBRARY_OUTPUT_DIRECTORY = ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
set(BUILD_LIB_DIR ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
file(MAKE_DIRECTORY ${BUILD_LIB_DIR})
message("Build lib directory ensured: ${BUILD_LIB_DIR}")
# ==============================
# Step 8: Copy .so files with proper build rules
# ==============================
foreach(module IN LISTS OPENCV_MODULES)
set(SRC_SO "${OPENCV_LIB_DIR}/lib${module}.so")
set(DST_SO "${BUILD_LIB_DIR}/lib${module}.so")
message("Processing module: ${module}")
message(" Source: ${SRC_SO}")
message(" Destination: ${DST_SO}")
if(NOT EXISTS ${SRC_SO})
message(" ERROR: Missing source .so file!")
else()
message(" Source .so exists")
endif()
# 创建复制规则(Ninja 可以调度)
add_custom_command(
OUTPUT ${DST_SO}
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_SO}" "${DST_SO}"
DEPENDS "${SRC_SO}"
COMMENT "Copying ${module} to build directory"
VERBATIM
)
# 创建一个自定义目标来触发复制
add_custom_target(copy_${module}_so ALL DEPENDS ${DST_SO})
# 创建 IMPORTED 库(用于链接)
add_library(${module} SHARED IMPORTED GLOBAL)
set_target_properties(${module} PROPERTIES
IMPORTED_LOCATION "${DST_SO}"
IMPORTED_NO_SONAME TRUE
)
# 确保在构建 entry 前完成复制
add_dependencies(entry copy_${module}_so)
endforeach()
# ==============================
# Step 9: Link dependencies
# ==============================
target_link_libraries(entry
PUBLIC
ace_napi.z
uv
pthread
z
m
${OPENCV_MODULES}
)
message("Linking completed for 'entry' with all OpenCV modules")
# ==============================
# Final message
# ==============================
message("Successfully configured OpenCV integration for entry library")
~~~
– 然后清理项目 注意删除.cxx文件夹 重新构建即可启动 此时,已可以在napi_init.cpp使用OpenCV库进行代码编辑。


