在这里插入图片描述

初识 OpenCV for Android

大家好,本篇文章将带你从零开始,在 Android 项目中集成 OpenCV,并使用 Native C++ 实现一张全屏的「Hello OpenCV」图像绘制。


什么是 OpenCV

OpenCV(Open Source Computer Vision Library)是一个开源计算机视觉库,用于图像处理、视频分析、特征检测、人脸识别、目标跟踪等。

在 Android 上,OpenCV 有两种使用方式:

  1. Java 版:简单、速度一般
  2. Native C++ 版:高性能、原生执行(本篇使用)

性能差距:复杂图像处理时,C++ 版本比 Java 快 3~10 倍

任务 Java 版耗时 Native(C++) 版耗时 差距
Hello World / 画文字 1ms 0.5ms 几乎一样
灰度化 (640x480) 8~12ms 2~3ms 快 3~5 倍
高斯模糊/边缘检测 20~40ms 5~8ms 快 4~6 倍
特征点检测(SIFT/SURF) 200ms+ 30~50ms 快 5~10 倍
4K 大图处理 经常卡顿 流畅 差距巨大

开发环境

  • Android Studio
  • NDK 27+
  • OpenCV Android SDK 4.8.0
  • Kotlin + build.gradle.kts
  • 真机(arm64-v8a)

OpenCV 下载

官网:https://opencv.org/releases/

下载:

OpenCV-4.8.0-android.zip

解压备用。


项目结构(必须严格对应)

app/
 ├── src/main/
 │    ├── cpp/
 │    │   ├── opencv/include/      <-- OpenCV 头文件
 │    │   ├── native-lib.cpp       <-- C++ 代码
 │    │   └── CMakeLists.txt       <-- C++ 构建配置
 │    ├── jniLibs/
 │    │   ├── arm64-v8a/
 │    │   ├── armeabi-v7a/
 │    │   └── ...其他架构
 │    ├── res/layout/activity_main.xml
 │    └── java/.../MainActivity.kt
 └── build.gradle.kts

项目实例

开源库:gitee仓库

CMakeLists.txt

cmake_minimum_required(VERSION 3.22.1)
project(nativeopencv)

# OpenCV 头文件
include_directories(${CMAKE_SOURCE_DIR}/opencv/include)

# OpenCV 库路径
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
link_directories(${OpenCV_DIR})

# 编译自己的 so
add_library(
        native-lib
        SHARED
        native-lib.cpp
)

# 链接库
target_link_libraries(
        native-lib
        opencv_java4
        log
        jnigraphics
        android
)

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_show"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MainActivity.kt

package com.nicoli.helloopencv

import android.graphics.Bitmap
import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 获取屏幕宽高
        val display = windowManager.defaultDisplay
        val size = android.graphics.Point()
        display.getSize(size)
        val w = size.x
        val h = size.y

        val iv = findViewById<ImageView>(R.id.iv_show)
        iv.setImageBitmap(getHelloOpenCVBitmap(w, h))
    }

    // 调用 C++ 函数
    private external fun getHelloOpenCVBitmap(width: Int, height: Int): Bitmap

    companion object {
        init {
            System.loadLibrary("opencv_java4")
            System.loadLibrary("native-lib")
        }
    }
}

native-lib.cpp

// JNI 基础头文件
#include <jni.h>

// OpenCV 核心头文件
#include <opencv2/opencv.hpp>

// Android Bitmap 操作库
#include <android/bitmap.h>

// 使用 OpenCV 命名空间
using namespace cv;

/**
 * 供 Kotlin 调用的 JNI 函数
 * 函数名规则:Java_包名_类名_方法名
 *
 * @param env JNI 环境
 * @param thiz 当前 Activity 对象
 * @param width 屏幕宽
 * @param height 屏幕高
 * @return Bitmap 对象
 */
extern "C"
JNIEXPORT jobject JNICALL
Java_com_nicoli_helloopencv_MainActivity_getHelloOpenCVBitmap(
        JNIEnv *env,
        jobject thiz,
        jint width,
        jint height
) {
    // ==========================
    // 1. 创建与屏幕一样大的黑色图像
    // ==========================
    // Mat:OpenCV 存储图像的类
    // 高、宽、图像类型(CV_8UC3=彩色图)、颜色(0,0,0=黑色)
    Mat mat(height, width, CV_8UC3, Scalar(0, 0, 0));

    // ==========================
    // 2. 在图像上绘制绿色文字
    // ==========================
    putText(
            mat,                        // 目标图像
            "Hello, OpenCV!",           // 文字内容
            Point(width/2 - 230, height/2), // 位置(居中)
            FONT_HERSHEY_SIMPLEX,       // 字体
            3.0,                        // 字体大小
            Scalar(0, 255, 0),          // 颜色:绿色(BGR)
            5                           // 文字粗细
    );

    // ==========================
    // 3. 颜色格式转换
    // OpenCV:BGR
    // Android:RGBA
    // ==========================
    cvtColor(mat, mat, COLOR_BGR2RGBA);

    // ==========================
    // 4. 创建 Android Bitmap
    // ==========================
    jclass bmpCls = env->FindClass("android/graphics/Bitmap");
    jclass configCls = env->FindClass("android/graphics/Bitmap$Config");

    // 获取 ARGB_8888 配置
    jfieldID argbField = env->GetStaticFieldID(configCls, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
    jobject config = env->GetStaticObjectField(configCls, argbField);

    // 创建 Bitmap
    jmethodID createBmp = env->GetStaticMethodID(bmpCls, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
    jobject bitmap = env->CallStaticObjectMethod(bmpCls, createBmp, width, height, config);

    // ==========================
    // 5. 将 Mat 数据写入 Bitmap
    // ==========================
    void *pixels;

    // 锁定 Bitmap 内存
    AndroidBitmap_lockPixels(env, bitmap, &pixels);

    // 拷贝图像数据
    memcpy(pixels, mat.data, mat.total() * mat.elemSize());

    // 解锁
    AndroidBitmap_unlockPixels(env, bitmap);

    // 返回 Bitmap 给 Kotlin
    return bitmap;
}

在这里插入图片描述


核心知识点总结

Mat 类

1. 定义

Mat = Matrix(矩阵)
OpenCV 中存储图像的基础数据结构

你可以把它理解为:
一张图片 = 一个数字矩阵

2. 作用

  • 存储图像像素数据
  • 存储图像宽、高、通道数、深度
  • 所有 OpenCV 操作都围绕 Mat 展开

3. 类结构(简化版)

class Mat
{
public:
    int rows;       // 高
    int cols;       // 宽
    int channels(); // 通道数:彩色图3,灰度图1
    uchar* data;    // 像素数据指针
};

4. 继承关系(OpenCV 官方继承链)

Mat
 ↑
MatExpr
 ↑
Matx
 ↑
InputArray / OutputArray

真正重要的继承关系(实际开发):

Mat
 ↑
UMat (用于OpenCL加速)
 ↑
cuda::GpuMat (GPU加速)

5. 图像类型解释

  • CV_8UC1 → 8 位灰度图
  • CV_8UC3 → 8 位彩色图(BGR)
  • CV_8UC4 → 8 位带透明通道(RGBA)

6. 我们代码中的 Mat

Mat mat(height, width, CV_8UC3, Scalar(0, 0, 0));
  • 高 height
  • 宽 width
  • 3 通道彩色图
  • 黑色背景

putText 函数(绘制文字)

1. 作用

在图像上绘制文字

2. 归属

属于 imgproc 模块 的绘图功能。

3. 函数原型

void putText(
    InputArray img,      // 输入图像(Mat)
    const String& text,  // 文字
    Point org,           // 文字位置
    int fontFace,        // 字体
    double fontScale,    // 字体大小
    Scalar color,        // 颜色
    int thickness = 1    // 粗细
);

4. 继承关系

putText 不是类,是全局函数,但它操作的类关系:

drawMarker
putText     → 都继承自:DrawingFunctions
line
rectangle
circle

5. 代码中的使用

putText(
    mat,
    "Hello, OpenCV!",
    Point(width/2 - 230, height/2),
    FONT_HERSHEY_SIMPLEX,
    3.0,
    Scalar(0,255,0),
    5
);

cvtColor 函数(颜色空间转换)

1. 作用

转换图像的颜色格式

2. 为什么必须用?

  • OpenCV 默认:BGR
  • Android Bitmap 默认:RGBA
    颜色顺序不一样,必须转换!

3. 函数原型

void cvtColor(
    InputArray src,   // 源图像
    OutputArray dst,  // 目标图像
    int code,         // 转换类型
    int dstCn = 0
);

4. 常用转换

  • COLOR_BGR2GRAY → 彩色转灰度
  • COLOR_BGR2RGB → BGR 转 RGB
  • COLOR_BGR2RGBA → BGR 带透明通道

5. 代码中的作用

cvtColor(mat, mat, COLOR_BGR2RGBA);

把 OpenCV 格式 → 转为 Android 能显示的格式。


最重要的三张继承图

1. 图像数据容器继承图

          BaseMat
            ↑
          -------
          ↑     ↑
        Mat     SparseMat
        ↑
      UMat
        ↑
  cuda::GpuMat

2. 绘图功能关系

DrawingFunctions
   ↑ ↑ ↑ ↑ ↑
putText
rectangle
circle
line
drawMarker

3. 颜色转换模块

ColorProcessing
      ↑
   cvtColor
      ↑
COLOR_BGR2GRAY
COLOR_BGR2RGB
COLOR_BGR2HSV
...

结语

这篇文章带你完成了 Android + OpenCV + Native C++ 的第一个真正原生项目。

OpenCV 非常强大,从简单的绘图到复杂的 AI 视觉算法都能轻松实现。Native 开发虽然配置稍复杂,但换来的是极致性能

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐