背景
我们需要编一个可执行文件,实现图像在手机中的处理,最好做到直接通过调用adb 指令运行。
我的电脑的环境:
ubuntu 18
cmake 3.10
我选用的都是最新的版本的opencv 和最新的android sdk,
opencv:4.9.0
android sdk:android-ndk-r26d
STEP1 : 环境搭建
- 配置cmake
- 由于opencv现在已经迭代到4.9了,其编译对cmake的版本也有要求,要求cmake必须要在3.19版本以上,我的本地版本是3.10的,于是需要更新到最新的,直接去 cmake 官网下载最最新的,编译安装:
cd cmake-3.30.0
mkdir build
cd build
cmake ..
make -j8
- 下载androd NDK
https://developer.android.google.cn/ndk/downloads?hl=zh-cn
- 下载opencv SDK
https://opencv.org/releases/
- 直接下载android 版本的,解压到本地固定位置。
STEP2:opencv配置
opencv由于直接下载的是SDK ,所以不需要过多的处理,cmake可以直接调用,我们只需要知道几个重点东西就可以了
-
库函数:
包含了3大块,三方库,静态库,和其他的东西,这里静态库是个重点
静态库里core 和imgproc是最基础的,其他都是一些特殊功能。 -
头文件:
opencv-4.9.0-android-sdk/OpenCV-android-sdk/sdk/native/jni/include
- 这个是主要的头文件路径
-
cmake file
opencv-4.9.0-android-sdk/OpenCV-android-sdk/sdk/native/jni/abi-arm64-v8a
- 这个路径是一会儿要自动配置三方库搜索的路径,也比较重要
STEP3:Cmake 配置
- CMakeLists.txt 的编写背景知识:
参考一下我之前写的编写方法
https://editor.csdn.net/md/?articleId=140210286
- CMakeLists.txt 的编写
#****************************This is Project Info****************************
cmake_minimum_required(VERSION 3.4)
# 设置项目名称和版本
project(app1 VERSION 1.0)
set(ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set(OUT_PATH ${CMAKE_BINARY_DIR})
set(NDK_PATH /home/dzk/disk/android_ndk/android-ndk-r26d)
MESSAGE(STATUS "This is ROOT_PATH dir " ${ROOT_PATH})
MESSAGE(STATUS "This is OUT_PATH dir " ${OUT_PATH})
MESSAGE(STATUS "This is NDK_PATH dir " ${NDK_PATH})
MESSAGE(STATUS "This is OPENCV_PATH dir " ${OPENCV_PATH})
add_definitions("-Wall -g")
#设置交叉编译环境和工具
set(CMAKE_SYSTEM_NAME Android) #要构建的目标平台,比如要构建成android平台的
set(CMAKE_SYSTEM_PROCESSOR arm) #是要构建的目标体系结构,这个平台是什么架构,一般是arm
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a) #编译的二进制接口(armeabi-v7a、arm64-v8a、x86、x86_64)
set(CMAKE_ANDROID_NDK /home/dzk/disk/android_ndk/android-ndk-r26d) #andorid ndk的位置,可以从https://developer.android.google.cn/ndk/downloads?hl=zh-cn 下载最新的
#选用编译器,我选用的是clang++ 的编译器,当然也可以选择g++的,只不过android NDK 后面好像不支持g++了
#这里有个重点,即尽量选用NDK 里面的clang++, 如果不使用NDK 的clang,就会出现生成的可执行文件64位和32位不匹配的问题
set(triple arm-linux-gnueabihf)
set(CMAKE_ANDROID_TOOLCHAIN /home/dzk/disk/android_ndk/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang++)
set(CMAKE_CXX_COMPILER /home/dzk/disk/android_ndk/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_C_COMPILER /home/dzk/disk/android_ndk/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang)
set(CMAKE_SYSTEM_VERSION 21) # API level 21, 这里和上面的版本是一致的,也可以不一样
set(CMAKE_ANDROID_PLATFORM android-21)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_ANDROID_STL c++_shared)
#set(CMAKE_ANDROID_STL_TYPE gnustl_static) #制定的c++ stl 库类型,可以设置
#大概意思可能是选用NDK 里面的cmake,我试过不加好像也可以
set(CMAKE_TOOLCHAIN_FILE /home/dzk/disk/android_ndk/android-ndk-r26d/build/cmake/android.toolchain.cmake)
########################opencv start###############################
set(OPENCV_PATH ${ROOT_PATH}/lib/opencv-4.9.0)
#set(OpenCVSDK /home/dzk/disk/android_ndk/opencv-install/sdk/native)
set(OpenCVSDK /home/dzk/disk/android_ndk/opencv-4.9.0-android-sdk/OpenCV-android-sdk/sdk/native)
set(CMAKE_PREFIX_PATH "/home/dzk/disk/android_ndk/opencv-4.9.0-android-sdk/OpenCV-android-sdk/sdk/native/jni/abi-arm64-v8a")
find_package(OpenCV REQUIRED)
include_directories(${OpenCVSDK}/jni/include)
link_directories(${OpenCVSDK}/staticlibs/arm64-v8a
${OpenCVSDK}/3rdparty/libs/arm64-v8a
${OpenCVSDK}/libs/arm64-v8a)
#我只用到了简单函数,就没有包含太多的库文件
link_libraries(
log
opencv_imgproc
opencv_imgcodecs
opencv_core
)
########################opencv end###############################
add_executable(myapp
main.cpp
)
target_link_libraries(myapp ${link_libraries})
- 重点
这里有几个重点,当时困惑了许久
重点1:应用引用opencv库的方法
set(CMAKE_PREFIX_PATH "/home/dzk/disk/android_ndk/opencv-4.9.0-android-sdk/OpenCV-android-sdk/sdk/native/jni/abi-arm64-v8a")
find_package(OpenCV REQUIRED)
这两个指令非常关键,上面一个是设置了opencv SDK 库的路径,下边一个是cmake会自动找这个路径下边的需要的opencv包。否则无法直接调用opencv sdk。
STEP4 : 实现效果
代码:实现一个图片转灰度图的功能:
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
printf("hello dzk");
//read picture
Mat img = cv::imread("/sdcard/0_0_2_4096x3072.jpeg");
Mat gray_image;
cvtColor(img, gray_image, COLOR_BGR2GRAY);
imwrite("/sdcard/gray.jpg", gray_image);
printf("end");
return 0;
}
先cmake … 再make 就可以编译出可执行文件,推到手机vendor/bin 目录下,通过
adb shell myapp
调用即可
处理后的两张图:
遇到的问题
- 找不到print 函数:
需要在cmake txt里面加入log库: