在Android上玩转Opencv 系列:17.基础知识 模版匹配

196 阅读2分钟

在 Android 版本的 OpenCV 中,可以使用 matchTemplate 进行模板匹配(Template Matching)。下面是详细的步骤和示例代码:

步骤

  1. 引入 OpenCV

确保你的 Android 项目已经集成了 OpenCV,可以使用 OpenCV SDK 或者 OpenCV Android 绑定(OpenCV Android SDK)。

  1. 加载图像

目标图像(需要搜索的图像)和模板图像(要匹配的部分)。

  1. 模板匹配

使用 Imgproc.matchTemplate() 进行匹配。

  1. 获取匹配位置

通过 Core.minMaxLoc() 找到最佳匹配位置。

  1. 绘制匹配结果

在原图上绘制一个矩形框标记匹配位置。

示例代码

import org.opencv.android.Utils;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import android.graphics.Bitmap;

public class TemplateMatching {

    public static Bitmap matchTemplate(Bitmap sourceBitmap, Bitmap templateBitmap) {
        // 将 Bitmap 转换为 Mat
        Mat sourceMat = new Mat();
        Mat templateMat = new Mat();
        Utils.bitmapToMat(sourceBitmap, sourceMat);
        Utils.bitmapToMat(templateBitmap, templateMat);

        // 创建存放匹配结果的 Mat
        int resultCols = sourceMat.cols() - templateMat.cols() + 1;
        int resultRows = sourceMat.rows() - templateMat.rows() + 1;
        Mat result = new Mat(resultRows, resultCols, CvType.CV_32FC1);

        // 进行模板匹配 (TM_CCOEFF_NORMED 是常用的一种)
        Imgproc.matchTemplate(sourceMat, templateMat, result, Imgproc.TM_CCOEFF_NORMED);

        // 获取最佳匹配位置
        Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
        Point matchLoc = mmr.maxLoc; // maxLoc 对应 TM_CCOEFF_NORMED

        // 在原图上绘制匹配位置
        Imgproc.rectangle(sourceMat, matchLoc,
                new Point(matchLoc.x + templateMat.cols(), matchLoc.y + templateMat.rows()),
                new Scalar(0, 255, 0), 3);

        // 转换回 Bitmap 以便显示
        Bitmap outputBitmap = Bitmap.createBitmap(sourceMat.cols(), sourceMat.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(sourceMat, outputBitmap);

        return outputBitmap;
    }
}

template_match.png 关键点解析

  1. 匹配方法选择(Imgproc.matchTemplate)

• Imgproc.TM_CCOEFF_NORMED(推荐,归一化互相关系数)

• Imgproc.TM_SQDIFF(平方差)

• Imgproc.TM_CCORR(相关性)

• Imgproc.TM_CCORR_NORMED(归一化相关性)

• Imgproc.TM_SQDIFF_NORMED(归一化平方差)

一般建议使用 TM_CCOEFF_NORMED,因为它对光照变化影响较小。

  1. Core.minMaxLoc(result) 解析

• minLoc 和 maxLoc 返回的是匹配值最小和最大的像素坐标。

• TM_CCOEFF_NORMED 选择 maxLoc 作为匹配点。

• TM_SQDIFF 选择 minLoc 作为匹配点。

  1. 绘制匹配框

• Imgproc.rectangle() 用于在匹配区域画矩形框。

在 Android 上使用 OpenCV

如果你还没有集成 OpenCV,可以按照以下步骤:

  1. 添加 OpenCV 依赖

• 在 app/build.gradle 中添加:

implementation 'org.opencv:opencv-android:4.5.1'

• 或者使用 OpenCV SDK,并在 CMakeLists.txt 或 gradle 中手动配置。

  1. 在 MainActivity.java 中初始化 OpenCV
import org.opencv.android.OpenCVLoader;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (!OpenCVLoader.initDebug()) {
        Log.e("OpenCV", "OpenCV 初始化失败!");
    } else {
        Log.d("OpenCV", "OpenCV 初始化成功!");
    }
}

总结

• Imgproc.matchTemplate() 是 OpenCV 提供的标准模板匹配方法,适用于静态目标匹配。

• 使用 Core.minMaxLoc() 找到最佳匹配位置。

• TM_CCOEFF_NORMED 是最常用的匹配方法。

• 适用于简单的匹配任务,不适用于旋转、缩放等复杂情况(可以使用特征匹配如 SIFT/SURF/ORB 进行改进)。

如果你需要更高级的匹配(例如旋转/缩放不变),可以考虑 ORB/SIFT/SURF 特征匹配