在Windows上编译OpenCV Android原生库全记录

无需Android Studio,脱离复杂的Gradle构建系统,仅用命令行工具完成OpenCV Android .so库的编译

前言

最近在开发一个需要集成OpenCV的Android项目时,我发现传统的Android Studio集成方式存在一些限制:构建流程不透明、难以自定义模块、集成到CI/CD流程复杂。经过一番探索,我成功找到了一种纯命令行编译OpenCV Android库的方法,整个过程完全掌控,非常适合需要自定义构建或自动化集成的场景。

本文将详细介绍我在Windows 11环境下,使用Git Bash、Android NDK、CMake和Ninja,从源码编译OpenCV 4.11.0 Android原生库的完整过程。

环境准备

在开始之前,需要确保你的系统已安装以下工具:

工具 版本要求 作用

Android NDK ≥ r21(推荐r26) Android原生开发工具链

CMake ≥ 3.18 跨平台构建系统

Git for Windows 最新版 提供Bash环境

Ninja 最新版 高性能构建系统

工具路径示例

我的实际环境配置如下:

· OpenCV源码:D:\opencv-4.11.0

· Android NDK:D:\AndroidSDK\ndk\26.3.11579264

· CMake:D:\AndroidSDK\cmake\3.22.1\bin\cmake

· Ninja:D:\ndkTest\ninja-win\ninja.exe

核心编译脚本

经过多次调试和优化,我总结出了以下可靠的编译脚本。这个脚本成功编译出了15个OpenCV Android动态库,总大小约300MB。

bash 复制代码
#!/bin/bash
# ============================================
# OpenCV 4.11.0 Android 纯命令行编译脚本
# ============================================

set -e  # 出错即停止

# === 配置 ===
OPENCV_SRC="/d/opencv-4.11.0"
NDK_PATH="/d/AndroidSDK/ndk/26.3.11579264"
CMAKE_BIN="/d/AndroidSDK/cmake/3.22.1/bin/cmake"
NINJA_BIN="/d/ndkTest/ninja-win/ninja.exe"

# === 编译选项 ===
ABI="arm64-v8a"  # 目标架构
API_LEVEL=24      # Android API级别
BUILD_TYPE="Release"  # 构建类型
BUILD_DIR="/d/opencv_build_${ABI}"  # 构建目录
INSTALL_DIR="/d/opencv-android-output"  # 输出目录

echo "========================================"
echo "🚀 OpenCV 4.11.0 Android 纯命令行编译"
echo "========================================"

# 环境检查
check_environment() {
    echo "🔍 环境检查..."
    [ -d "$OPENCV_SRC" ] || { echo "❌ OpenCV源码不存在: $OPENCV_SRC"; exit 1; }
    [ -f "$OPENCV_SRC/CMakeLists.txt" ] || { 
        echo "❌ OpenCV/CMakeLists.txt不存在"; exit 1; 
    }
    [ -f "$CMAKE_BIN" ] || { echo "❌ CMake不存在: $CMAKE_BIN"; exit 1; }
    [ -f "$NINJA_BIN" ] || { echo "❌ Ninja不存在: $NINJA_BIN"; exit 1; }
    [ -f "$NDK_PATH/build/cmake/android.toolchain.cmake" ] || { 
        echo "❌ NDK android.toolchain.cmake不存在"; exit 1; 
    }
    echo "✅ 环境检查通过"
}

# 清理构建目录
clean_build_dir() {
    echo "🧹 清理构建目录..."
    rm -rf "$BUILD_DIR"
    mkdir -p "$BUILD_DIR"
    cd "$BUILD_DIR"
}

# CMake配置
configure_cmake() {
    echo "⚙️ CMake配置..."
    echo "  构建目录: $BUILD_DIR"
    echo "  源码目录: $OPENCV_SRC"

    "$CMAKE_BIN" \
        "$OPENCV_SRC" \
        -G "Ninja" \
        -DCMAKE_MAKE_PROGRAM="$NINJA_BIN" \
        -DCMAKE_TOOLCHAIN_FILE="$NDK_PATH/build/cmake/android.toolchain.cmake" \
        -DANDROID_ABI="$ABI" \
        -DANDROID_PLATFORM="android-$API_LEVEL" \
        -DANDROID_STL="c++_shared" \
        -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
        -DBUILD_JAVA=OFF \
        -DBUILD_opencv_java=OFF \
        -DBUILD_SHARED_LIBS=ON \
        -DBUILD_opencv_core=ON \
        -DBUILD_opencv_imgproc=ON \
        -DBUILD_opencv_imgcodecs=ON \
        -DBUILD_TESTS=OFF \
        -DBUILD_EXAMPLES=OFF \
        -DBUILD_PERF_TESTS=OFF \
        -DBUILD_ANDROID_EXAMPLES=OFF \
        -DBUILD_ANDROID_PROJECTS=OFF

    [ $? -eq 0 ] && echo "✅ CMake配置成功" || {
        echo "❌ CMake配置失败"; exit 1
    }
}

# 编译OpenCV
compile_opencv() {
    echo "🔨 开始编译..."
    "$CMAKE_BIN" --build . --parallel 8
    [ $? -eq 0 ] && echo "✅ 编译成功" || {
        echo "❌ 编译失败"; exit 1
    }
}

# 整理输出文件
collect_output() {
    echo "📦 整理输出文件..."
    rm -rf "$INSTALL_DIR"
    mkdir -p "$INSTALL_DIR/libs/$ABI"
    mkdir -p "$INSTALL_DIR/include"

    # 复制.so文件
    echo "  复制.so文件..."
    if [ -d "lib" ]; then
        SO_PATHS=("lib/$ABI/*.so" "lib/*.so" "*.so" "bin/*.so")
        for pattern in "${SO_PATHS[@]}"; do
            if ls $pattern 1>/dev/null 2>&1; then
                echo "    找到文件: $pattern"
                cp $pattern "$INSTALL_DIR/libs/$ABI/" 2>/dev/null || true
            fi
        done
    fi

    # 复制头文件
    echo "  复制头文件..."
    cp -r "$OPENCV_SRC/include/opencv2" "$INSTALL_DIR/include/" 2>/dev/null || true

    # 统计结果
    local SO_COUNT=$(ls "$INSTALL_DIR/libs/$ABI/"*.so 2>/dev/null | wc -l)
    echo ""
    echo "========================================"
    echo "🎉 编译完成!"
    echo "========================================"
    echo "📊 结果统计:"
    echo "  架构:$ABI"
    echo "  API Level:$API_LEVEL"
    echo "  构建类型:$BUILD_TYPE"
    echo "  库文件数量:$SO_COUNT 个"
    echo "  输出目录:$INSTALL_DIR"
}

# 主流程
main() {
    check_environment
    clean_build_dir
    configure_cmake
    compile_opencv
    collect_output
}

main "$@"

编译过程详解

  1. 关键配置项解析

脚本中的CMake配置选项是编译成功的关键:

bash 复制代码
# 禁用Java绑定 - 避免与Android构建系统冲突
-DBUILD_JAVA=OFF
-DBUILD_opencv_java=OFF

# 禁用Android示例项目 - 简化构建流程
-DBUILD_ANDROID_EXAMPLES=OFF
-DBUILD_ANDROID_PROJECTS=OFF

# 启用动态库构建
-DBUILD_SHARED_LIBS=ON

# 使用c++_shared STL - 确保运行时兼容性
-DANDROID_STL="c++_shared"

# 仅启用核心模块(可按需添加更多)
-DBUILD_opencv_core=ON
-DBUILD_opencv_imgproc=ON
-DBUILD_opencv_imgcodecs=ON
  1. 编译输出结果

执行脚本后,成功编译出15个OpenCV动态库:

库文件 大小 核心功能

libopencv_core.so 23MB 核心数据结构与算法

libopencv_imgproc.so 25MB 图像处理(滤波、变换等)

libopencv_dnn.so 87MB 深度学习模块

libopencv_imgcodecs.so 23MB 图像编解码(JPEG、PNG等)

libopencv_calib3d.so 20MB 相机标定与3D重建

libopencv_features2d.so 6.2MB 特征检测与匹配

libopencv_gapi.so 76MB 图像处理流水线框架

其他8个模块 总计~40MB ML、视频处理等

  1. 编译耗时统计

· CMake配置阶段:约2-3分钟

· 编译阶段:约20-30分钟(1340个构建任务)

· 总计:约25-35分钟(取决于CPU性能)

在Android项目中的使用

  1. CMake集成示例

在Android项目的CMakeLists.txt中添加以下配置:

cmake 复制代码
cmake_minimum_required(VERSION 3.18.1)
project("MyOpenCVApp")

# 设置OpenCV路径
set(OPENCV_ANDROID_DIR "/d/opencv-android-output")

# 包含头文件
include_directories(${OPENCV_ANDROID_DIR}/include)

# 添加你的原生库
add_library(native-lib SHARED
    native-lib.cpp
)

# 链接OpenCV库
target_link_libraries(native-lib
    ${OPENCV_ANDROID_DIR}/libs/${ANDROID_ABI}/libopencv_core.so
    ${OPENCV_ANDROID_DIR}/libs/${ANDROID_ABI}/libopencv_imgproc.so
    # ... 其他需要的库
    log
    android
)
  1. JNI简单测试

创建一个简单的JNI函数测试OpenCV功能:

cpp 复制代码
#include <jni.h>
#include <android/log.h>
#include <opencv2/opencv.hpp>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_testOpenCV(
        JNIEnv* env,
        jobject /* this */) {
    
    // 创建测试图像
    cv::Mat testMat(100, 100, CV_8UC3, cv::Scalar(0, 255, 0));
    
    // 转换为灰度
    cv::Mat grayMat;
    cv::cvtColor(testMat, grayMat, cv::COLOR_BGR2GRAY);
    
    std::string result = "OpenCV 4.11.0工作正常!\n";
    result += "图像尺寸: " + std::to_string(testMat.cols) + 
              "x" + std::to_string(testMat.rows);
    
    return env->NewStringUTF(result.c_str());
}

常见问题与解决方案

问题1:CMake配置失败

症状:CMake Error: The source directory does not appear to contain CMakeLists.txt

解决:

bash 复制代码
# 验证OpenCV源码路径
ls -la "/d/opencv-4.11.0/CMakeLists.txt"

# 确保使用的是正确的路径格式(Git Bash使用正斜杠)

问题2:编译时内存不足

症状:编译过程卡住或编译器被杀死

解决:

bash 复制代码
# 减少并行编译线程数
"$CMAKE_BIN" --build . --parallel 4  # 改为4线程

# 关闭其他内存占用大的程序

问题3:生成的.so文件找不到

症状:编译成功但输出目录为空

解决:

bash 复制代码
# 手动查找.so文件
find "/d/opencv_build_arm64-v8a" -name "*.so" -type f

# 检查lib目录结构
ls -la "/d/opencv_build_arm64-v8a/lib/"

进阶优化

  1. 多ABI架构支持

修改脚本支持批量编译多个架构:

bash 复制代码
#!/bin/bash
# 批量编译多个ABI

ABI_LIST=("arm64-v8a" "armeabi-v7a" "x86_64")

for ABI in "${ABI_LIST[@]}"; do
    echo "开始编译 $ABI ..."
    # 修改ABI变量并重新执行编译逻辑
    BUILD_DIR="/d/opencv_build_${ABI}"
    # ... 编译流程
done
  1. 模块化定制

根据项目需求选择编译的模块:

bash 复制代码
# 基础图像处理配置(最小化)
-DBUILD_LIST="core,imgproc,imgcodecs"

# 计算机视觉项目配置
-DBUILD_opencv_calib3d=ON
-DBUILD_opencv_features2d=ON
-DBUILD_opencv_objdetect=ON

# 禁用不需要的模块以减少体积
-DBUILD_opencv_dnn=OFF
-DBUILD_opencv_gapi=OFF

总结

通过纯命令行方式编译OpenCV Android库,我获得了以下优势:

  1. 完全掌控构建过程:可以精确控制编译选项和模块
  2. 脱离Android Studio依赖:适合CI/CD自动化流程
  3. 定制化程度高:按需编译,减少应用体积
  4. 学习价值大:深入理解OpenCV构建系统

这种编译方式特别适合:

· 需要特定OpenCV配置的项目

· 对应用体积敏感的生产环境

· 自动化构建和部署流程

· 学习和研究OpenCV内部结构

希望这篇记录能帮助到有类似需求的开发者。如果在实践过程中遇到问题,欢迎留言讨论。


相关资源:

· OpenCV官方源码

· Android NDK下载

· 完整脚本下载

编译环境:Windows 11 + Git Bash + Android NDK r26 + OpenCV 4.11.0

相关推荐
我命由我1234510 小时前
Kotlin 面向对象 - 装箱与拆箱
android·java·开发语言·kotlin·android studio·android jetpack·android-studio
我命由我1234510 小时前
Android Jetpack Compose - Snackbar、Box
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
stevenzqzq10 小时前
android 日志过滤说明
android·日志过滤
游戏开发爱好者810 小时前
如何使用 AppUploader 提交上传 iOS 应用
android·ios·小程序·https·uni-app·iphone·webview
非凡ghost10 小时前
3C一体工具箱安卓版(手机维护工具箱)
android·学习·智能手机·软件需求
Jennifer33K10 小时前
AndroidStudio报错:minSdk(APl 33)> deviceSdk(APl 30)
android·gradle·android studio
alexhilton19 小时前
Jetpack Compose内部的不同节点类型
android·kotlin·android jetpack
Frank_HarmonyOS21 小时前
Android中四大组件之一的Activity的启动模式
android
似霰21 小时前
HIDL Hal 开发笔记7----简单 HIDL HAL 实现
android·framework·hal