基于形状的模板匹配,十字识别,C++/C#

在计算机视觉领域,基于形状的模板匹配是一项非常实用的技术,它可以帮助我们在复杂图像中精准定位特定形状的目标。今天咱们就来聊聊如何实现十字形状的识别,并且分别用C++和C#来实现。

C++ 实现

首先来看C++,OpenCV库为我们提供了强大的图像处理功能,在模板匹配这块也是相当给力。

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv) {
    // 读取模板图像(十字形状)
    Mat templateImage = imread("cross_template.png", IMREAD_GRAYSCALE);
    if (templateImage.empty()) {
        cout << "Could not open or find the template image" << endl;
        return -1;
    }

    // 读取待匹配的图像
    Mat inputImage = imread("input_image.png", IMREAD_GRAYSCALE);
    if (inputImage.empty()) {
        cout << "Could not open or find the input image" << endl;
        return -1;
    }

    // 定义结果矩阵
    Mat result;
    int result_cols = inputImage.cols - templateImage.cols + 1;
    int result_rows = inputImage.rows - templateImage.rows + 1;
    result.create(result_rows, result_cols, CV_32FC1);

    // 进行模板匹配,这里使用平方差匹配方法
    matchTemplate(inputImage, templateImage, result, TM_SQDIFF_NORMED);

    // 归一化结果便于显示
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

    // 寻找最佳匹配位置
    double minVal; double maxVal; Point minLoc; Point maxLoc;
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

    // 对于平方差匹配方法,最小值对应的位置就是最佳匹配位置
    Point matchLoc = minLoc;

    // 在原图上绘制矩形标记出匹配位置
    rectangle(inputImage, matchLoc, Point(matchLoc.x + templateImage.cols, matchLoc.y + templateImage.rows), Scalar(0, 255, 0), 2, 8, 0);

    // 显示结果
    imshow("Result", inputImage);
    waitKey(0);

    return 0;
}

C++ 代码分析

  1. 图像读取
    - imread函数分别读取模板图像(十字形状)和待匹配的图像。这里设置读取为灰度图像,因为在模板匹配中,灰度图像往往能满足需求且计算量更小。如果图像读取失败,程序会输出错误信息并退出。
  2. 结果矩阵创建
    - 根据模板图像和输入图像的大小计算结果矩阵的大小。结果矩阵的每个元素表示模板在对应位置的匹配程度。
  3. 模板匹配
    - 使用matchTemplate函数进行匹配,这里选用TMSQDIFFNORMED方法,它通过计算模板与图像块之间的平方差归一化来衡量匹配程度,值越小表示匹配越好。
  4. 寻找最佳匹配位置
    - minMaxLoc函数用于找到结果矩阵中的最小值和最大值及其位置。对于平方差匹配方法,最小值对应的位置就是最佳匹配位置。
  5. 标记与显示
    - 使用rectangle函数在输入图像上标记出匹配的位置,最后通过imshow显示结果。

C# 实现

接下来看看C#,Emgu CV库可以让我们在C#中轻松实现图像处理功能。

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System;
using System.Drawing;

class CrossTemplateMatching
{
    static void Main()
    {
        // 读取模板图像(十字形状)
        Image<Gray, byte> templateImage = new Image<Gray, byte>("cross_template.png");
        if (templateImage == null)
        {
            Console.WriteLine("Could not open or find the template image");
            return;
        }

        // 读取待匹配的图像
        Image<Gray, byte> inputImage = new Image<Gray, byte>("input_image.png");
        if (inputImage == null)
        {
            Console.WriteLine("Could not open or find the input image");
            return;
        }

        // 进行模板匹配,这里使用平方差匹配方法
        Image<Gray, float> result = inputImage.MatchTemplate(templateImage, TemplateMatchingType.CcoeffNormed);

        // 寻找最佳匹配位置
        double[] minValues;
        double[] maxValues;
        Point[] minLocations;
        Point[] maxLocations;
        result.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);

        // 对于平方差匹配方法,最小值对应的位置就是最佳匹配位置
        Point matchLoc = maxLocations[0];

        // 在原图上绘制矩形标记出匹配位置
        inputImage.Draw(new Rectangle(matchLoc, templateImage.Size), new Gray(255), 2);

        // 显示结果
        CvInvoke.Imshow("Result", inputImage);
        CvInvoke.WaitKey(0);
    }
}

C# 代码分析

  1. 图像读取
    - 使用Emgu CV的Image类型读取模板图像和输入图像。同样,如果图像读取失败,程序会输出错误信息并退出。
  2. 模板匹配
    - MatchTemplate函数进行模板匹配,这里选用TemplateMatchingType.CcoeffNormed方法,它基于归一化互相关系数来衡量匹配程度,值越大表示匹配越好(注意与C++中平方差匹配方法的区别)。
  3. 寻找最佳匹配位置
    - MinMax函数找到结果图像中的最小值和最大值及其位置。由于使用的匹配方法不同,这里取最大值对应的位置作为最佳匹配位置。
  4. 标记与显示
    - 使用Draw函数在输入图像上绘制矩形标记匹配位置,最后通过CvInvoke.Imshow显示结果。

通过上面两种语言的实现,我们可以看到虽然语法和使用的库有所不同,但基于形状的模板匹配实现十字识别的核心思路是相似的。希望这篇文章能帮助你在计算机视觉的形状匹配领域有所收获!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐