欢迎光临
我们一直在努力

基于OpenHarmony下的OpenCV库的交叉编译与实施

# 基于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库进行代码编辑。

赞(0)
未经允许不得转载:171主机测评 » 基于OpenHarmony下的OpenCV库的交叉编译与实施
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址