【问题标题】:opencv4android template matching using camera使用相机进行opencv4android模板匹配
【发布时间】:2025-12-29 21:55:12
【问题描述】:

我已下载并成功运行opencv4android sdk中提供的示例。

能够简单地显示相机帧而无需任何处理,

 public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
     return inputFrame.rgba();
 }

想用一些预定义的图像模板处理实时帧以识别该模板。我参考了this post 并相应地实施了。但我只会黑屏。

private Mat mCameraMat = new Mat();
private Mat mTemplateMat;

 public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    mCameraMat = inputFrame.rgba();
    initialize();

     int match_method = Imgproc.TM_SQDIFF;

        // Create the result matrix
        int result_cols = mCameraMat.cols() - mTemplateMat.cols() + 1;
        int result_rows = mCameraMat.rows() - mTemplateMat.rows() + 1;
        Log.d(TAG, " mCameraMat cols "+mCameraMat.cols());
        Log.d(TAG, " mCameraMat rows "+mCameraMat.rows());
        Log.d(TAG, " mTemplateMat cols "+mTemplateMat.cols());
        Log.d(TAG, " mTemplateMat rows "+mTemplateMat.rows());

       Mat result = new Mat(result_rows, result_cols, CvType.CV_32F);

        // Do the Matching and Normalize
        Imgproc.matchTemplate(mCameraMat, mTemplateMat, result, match_method);



        Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());

        // Localizing the best match with minMaxLoc
        MinMaxLocResult mmr = Core.minMaxLoc(result);

        Point matchLoc;
        if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) {
            matchLoc = mmr.minLoc;
        } else {
            matchLoc = mmr.maxLoc;
        }

        Rect roi = new Rect((int) matchLoc.x, (int) matchLoc.y, mTemplateMat.cols(), mTemplateMat.rows());
        Core.rectangle(mCameraMat, new Point(roi.x, roi.y), new Point(roi.width - 2, roi.height - 2), new Scalar(255, 0, 0, 255), 2);           
 return result;
}

public void initialize(){

    try {
        if (mCameraMat.empty())
            return;
        if(mTemplateMat == null){
            Mat temp = Utils.loadResource(Tutorial1Activity.this, R.drawable.icon);
            mTemplateMat = new Mat(temp.size(), CvType.CV_32F);
            Imgproc.cvtColor(temp, mTemplateMat, Imgproc.COLOR_BGR2RGBA);
            Log.d(TAG, "initialize mTemplateMat cols "+mTemplateMat.cols());
            Log.d(TAG, "initialize mTemplateMat rows "+mTemplateMat.rows());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意:

我的最终目标是通过实时摄像头识别扑克牌。请建议最佳方法。我应该使用图像模板还是其他任何东西来加快速度?

这就是我想从实时相机中识别多张卡片的方式:

当相机预览如下图时,结果应该是:♠A ♠K ♠Q ♠J ♠10

【问题讨论】:

  • 在我看来你的onCameraFrame 有两个return 语句,我错了吗?
  • @AlessandroJacopson:我在问题中发布代码时犯了错误。我现在已经更正了。
  • 我无法在 Android 上开发。在我看来,在调用Core.normalize 之后,图像result 中的最大灰度级将是1,对吗?如果是,那么在 0=black 和 255=white 范围内,result 几乎是黑色的。此外,result 的类型为CV_32F,而您可能需要一个 3 通道图像(如您在第一个代码 sn-p 中所写的 R、G、B,您说它工作正常)。而您的Core.rectangle 将在图像mCameraMat 上绘制,但您不会返回mCameraMat...
  • 图片的尺寸分别是多少?我首先将两个图像都转换为 8 位并检查结果。您可以保存生成的图像并查看,正如 Alessandro J 指出的那样,它可能是黑色的。
  • 所以模板图像是 72x72?您正在检查的图像的大小是多少?它们是相同的格式吗?让您自己更轻松地测试您的代码。拍摄图像,并从中裁剪出一部分。制作您的模板并通过您的代码运行它,如果您的代码没问题,那应该可以工作。选择模板图像是一门艺术,但首先要确保您的代码有效。

标签: android image-processing camera opencv4android


【解决方案1】:

模板匹配在这里不太可能是最好的方法。

  1. 尝试aSIFT 进行仿射不变 SIFT 匹配或正常 SIFT(存在 OpenCV 实现)。然而, 由于这些是 C++ 语言,您可能希望使用 JNI 在 Android 设备上从 Java 调用它。这可能是从 4 个符号中检测卡片花色的最佳方法。
  2. 检测和识别卡片上的数字/字母的另一种方法是使用像MSER 这样的文本检测器,然后在 MSER 过滤器指示的感兴趣区域上使用文本识别器。

在任何情况下,您都不太可能从您在图片中显示的那种图片中获得最佳效果。使用第一种方法,您可能能够获得可接受的完整正面、直立图像的性能。

【讨论】: