[学习OpenCV] Moment矩,轮廓特征,轮廓匹配,形状匹配 -2

Moment矩,Hu不变矩,轮廓匹配/形状匹配 -1 

Moment矩,轮廓特征,轮廓匹配,形状匹配 -2

目录

Moment矩,Hu不变矩,轮廓匹配/形状匹配 -1 

轮廓的基本概念与函数介绍

轮廓的基本概念

轮廓提取的基本原理:

边缘检测和轮廓提取的区别:

OpenCV轮廓提取相关函数介绍

1.轮廓提取

2. 多边形逼近

3. 几何距计算

提取与绘制轮廓API说明

 

轮廓特征属性及应用—位置关系及轮廓匹配

一、点与轮廓的距离及位置关系

二、轮廓的矩

三、形状匹配--matchShapes()

代码实现与演示

其他示例:目标识别——轮廓匹配

示例1:

示例2-1

示例2-2


轮廓的基本概念与函数介绍

轮廓的基本概念

       轮廓(Contours)可以说是一个很好的图像目标的外部特征,这种特征对于我们进行图像分析,目标识别和理解等更深层次的处理都有很重要的意义。简单说轮廓就是一些列点相连组成形状、它们拥有同样的颜色、轮廓发现在图像的对象分析、对象检测等方面是非常有用的工具,在OpenCV中使用轮廓发现相关函数时候要求输入图像是二值图像,这样便于轮廓提取、边缘提取等操作。

轮廓提取的基本原理:

(针对二值化的轮廓提取是这样的)对于一幅背景为白色、目标为黑色的二值图像,如果在图中找到一个黑色点,且它的8邻域(或4邻域)也均为黑色,则说明该点是目标的内部点,将其置为白色,视觉上就像内部被掏空一样;否则保持黑色不变,该点是目标的边界点。

边缘检测和轮廓提取的区别:

边缘检测主要是通过一些手段检测数字图像中明暗变化剧烈(即梯度变化比较大)像素点,偏向于图像中像素点的变化。如canny边缘检测,结果通常保存在和源图片一样尺寸和类型的边缘图中。
轮廓检测指检测图像中的对象边界,更偏向于关注上层语义对象。如OpenCV中的findContours()函数, 它会得到每一个轮廓并以点向量方式存储,除此也得到一个图像的拓扑信息,即一个轮廓的后一个轮廓、前一个轮廓、父轮廓和内嵌轮廓的索引编号。

 

OpenCV轮廓提取相关函数介绍

1.轮廓提取

在OpenCV中使用轮廓发现相关函数时候要求输入图像是二值图像,这样便于轮廓提取、边缘提取等操作。轮廓发现的函数与参数解释如下:

findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
- image输入/输出的二值图像
- mode 迒回轮廓的结构、可以是List、Tree、External
- method 轮廓点的编码方式,基本是基于链式编码
- contours 迒回的轮廓集合
- hieracrchy 迒回的轮廓层次关系
- offset 点是否有位移

2. 多边形逼近

多边形逼近,是通过对轮廓外形无限逼近,删除非关键点、得到轮廓的关键点,不断逼近轮廓真实形状的方法,OpenCV中多边形逼近的函数与参数解释如下:

approxPolyDP(curve, epsilon, closed, approxCurve=None)
- curve 表示输入的轮廓点集合
- epsilon 表示逼近曲率,越小表示相似逼近越厉害
- close 是否闭合

3. 几何距计算

图像几何距是图像的几何特征,高阶几何距中心化之后具有特征不变性,可以产生Hu距输出,用于形状匹配等操作,这里我们通过计算一阶几何距得到指定轮廓的中心位置,计算几何距的函数与参数解释如下:

moments(array, binaryImage=None)
- array表示指定输入轮廓
- binaryImage默认为None

提取与绘制轮廓API说明

在OpenCV里面利用findContours()函数和drawContours()函数实现这一功能。API介绍:

    C++:void findContours(InputOutputArray  image,
                           OutputArrayOfArrays  contours,
                           OutputArray  hierarchy,
                                int  mode,
                                int  method,
                                Point  offset = Point()
                            )   

参数详解:

参数一: image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;

参数二: contours是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。

参数三: hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为 默认值-1。

参数四: int型的mode,定义轮廓的检索模式:

模式一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略

模式二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,

模式三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层

模式四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。

参数五: int型的method,定义轮廓的近似方法:

方式一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内

方式二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours 向量内,拐点与拐点之间直线段上的信息点不予保留

方式三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

参数六: Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓 点上加上该偏移量,并且Point还可以是负值.

___________________________________________________________

    drawContours(
            //InputOutputArray  binImg, // 输出图像
            //OutputArrayOfArrays  contours,//  全部发现的轮廓对象
            //Int contourIdx// 轮廓索引号
            //const Scalar & color,// 绘制时候颜色
            //int  thickness,// 绘制线宽
            //int  lineType,// 线的类型LINE_8
            //InputArray hierarchy,// 拓扑结构图
            //int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓
            //Point offset = Point()// 轮廓位移,可选

 

轮廓特征属性及应用—位置关系及轮廓匹配

参考https://blog.csdn.net/abc8730866/article/details/69219992

1.计算点与轮廓的距离及位置关系——pointPolygonTest()

2.矩的计算——moments()

3.形状匹配(比较两个形状或轮廓间的相似度)——matchShapes()

先上ppt:

一、点与轮廓的距离及位置关系

 

二、轮廓的矩

轮廓矩的介绍:

 

三、形状匹配--matchShapes()

注意与模板匹配matchTemplate()相区分。形状匹配对于旋转、尺度、位移都能适应。

 

代码实现与演示

代码:1.计算点到轮廓的距离与位置关系

///计算点到轮廓的距离与位置关系
#include "opencv2/opencv.hpp"
using namespace cv;
#include <iostream>
using namespace std;
int main()
{
	//1.查找轮廓前的预处理
	Mat srcImg = imread("00.png",CV_LOAD_IMAGE_COLOR);
	Mat copyImg = srcImg.clone();
	cvtColor(srcImg,srcImg,CV_BGR2GRAY);
	threshold(srcImg,srcImg,100,255,CV_THRESH_BINARY);//确保黑中找白
	imshow("thresh",srcImg);
	//2.查找轮廓
	vector<vector<Point>> contours;
	findContours(srcImg,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);//最外层轮廓
	drawContours(copyImg, contours, -1, Scalar(0, 255, 0), 2, 8);
	//3.计算点到轮廓的距离与位置关系
	Point2f p1(20, 20);
	circle(copyImg,p1,3,Scalar(0,0,255),-1,8);
	double a0 = pointPolygonTest(contours[0], p1, true);//true表示点到轮廓的距离
	double b0 = pointPolygonTest(contours[0], p1, false);//false表示计算点与轮廓的位置关系
	cout << "a0=" << a0 << endl;
	cout << "b0=" << b0 << endl;
	imshow("contours",copyImg);
	waitKey(0);
	return 0;
}

运行结果:

  说明:a0之所以是负数,是因为点在轮廓外部

代码:2.轮廓矩的计算

///轮廓矩的计算
#include "opencv2/opencv.hpp"
using namespace cv;
#include <iostream>
using namespace std;
int main()
{
	//1.查找轮廓前的预处理
	Mat srcImg = imread("00.png", CV_LOAD_IMAGE_COLOR);
	Mat copyImg = srcImg.clone();
	cvtColor(srcImg, srcImg, CV_BGR2GRAY);
	threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY);//确保黑中找白
	imshow("thresh", srcImg);
	//2.查找轮廓
	vector<vector<Point>> contours;
	findContours(srcImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
	drawContours(copyImg, contours, -1, Scalar(0, 255, 0), 2, 8);
	//3.轮廓矩的计算
	Moments moments0 = moments(contours[0],false);//计算轮廓矩
	cout << moments0.m00<< endl;//输出空间矩之一的m00
	imshow("contours", copyImg);
	waitKey(0);
	return 0;
}

运行结果:

代码:3.形状匹配---比较两个形状或轮廓间的相似度

///形状匹配---比较两个形状或轮廓间的相似度
#include "opencv2/opencv.hpp"
using namespace cv;
#include <iostream>
using namespace std;
int main()
{
	//1.查找模版图像的轮廓
	Mat templateImg = imread("1.jpg", CV_LOAD_IMAGE_COLOR);
	Mat copyImg1 = templateImg.clone();
	cvtColor(templateImg, templateImg, CV_BGR2GRAY);
	threshold(templateImg, templateImg, 100, 255, CV_THRESH_BINARY);//确保黑中找白
	imshow("thresh1", templateImg);
	vector<vector<Point>> contours1;
	findContours(templateImg, contours1, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
	drawContours(copyImg1, contours1, -1, Scalar(0, 255, 0), 2, 8);
	//2.查找待测试图像的轮廓
	Mat testImg = imread("2.jpg", CV_LOAD_IMAGE_COLOR);
	Mat copyImg2 = testImg.clone();
	cvtColor(testImg, testImg, CV_BGR2GRAY);
	threshold(testImg, testImg, 100, 255, CV_THRESH_BINARY);//确保黑中找白
	imshow("thresh2", testImg);
	vector<vector<Point>> contours2;
	findContours(testImg, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
	//3.形状匹配---比较两个形状或轮廓间的相似度
	for (int i = 0; i < contours2.size();i++)//遍历待测试图像的轮廓
	{
		//返回此轮廓与模版轮廓之间的相似度,a0越小越相似
		double a0 = matchShapes(contours1[0],contours2[i],CV_CONTOURS_MATCH_I1,0);
		cout << "模版轮廓与待测试图像轮廓" << i << "的相似度:" << a0 << endl;//输出两个轮廓间的相似度
		if (a0<0.1)//如果此轮廓与模版轮廓的相似度小于0.1
		{
			drawContours(copyImg2, contours2, i, Scalar(0, 255, 0), 2, 8);//则在待测试图像上画出此轮廓
		}
		imshow("copyImg2", copyImg2);
		if (waitKey(0) == 27)//等待按键进行下一个轮廓,ESC则退出
		{
			cout << "ESC退出" << endl;
			break;
		}
	}
	waitKey(0);
	return 0;
}

运行结果:

 

其他示例:目标识别——轮廓匹配

示例1:

整个代码实现分为如下几步完成

  1. 加载图像,
  2. 图像二值化
  3. 轮廓发现
  4. 几何形状识别
  5. 测量周长、面积、计算中心
  6. 颜色提取

https://www.cnblogs.com/little-monkey/p/7475481.html

https://blog.csdn.net/abc8730866/article/details/69219992

//对轮廓按面积降序排列  
bool biggerSort(vector<Point> v1, vector<Point> v2)  
{  
    return contourArea(v1)>contourArea(v2);  
}  
 
 
int lunkuo()
{
    Mat img = imread("923.jpg",1);
    Mat img_template = imread("ljt.jpg",1);
 
    Mat gray_img,gray_img_template;
 
    cvtColor(img, gray_img, COLOR_BGR2GRAY);
    cvtColor(img_template, gray_img_template, COLOR_BGR2GRAY);
 
    Mat temp_img,temp_img_template;
 
    threshold(gray_img, temp_img, 60, 255, THRESH_BINARY);//对图像进行二值化
 
    threshold(gray_img_template, temp_img_template, 80, 255, THRESH_BINARY);
 
    Mat closerect=getStructuringElement(MORPH_RECT,Size(11,11)); //进行结构算子生成
 
    morphologyEx(temp_img, temp_img, MORPH_OPEN, closerect);
 
    morphologyEx(temp_img_template, temp_img_template, MORPH_OPEN, closerect);//进行形态学开运算
 
    imwrite("目标图处理.jpg",temp_img);
    imwrite("模版图处理.jpg",temp_img_template);
 
 
    vector<vector<Point>> contours_img,contours_template;//目标图,模版图
 
    findContours(temp_img, contours_img, CV_RETR_TREE, CHAIN_APPROX_NONE);//提取轮廓元素
 
    findContours(temp_img_template, contours_template, CV_RETR_TREE, CHAIN_APPROX_NONE);
 
    std::sort(contours_img.begin(), contours_img.end(), biggerSort);
 
    std::sort(contours_template.begin(), contours_template.end(), biggerSort);
 
    Rect rt;
 
    //for (int kk = 0; kk < contours_template.size(); kk++)
    //{
    //    rt = boundingRect(contours_template[kk]);
    //    rectangle(img_template, rt, Scalar(0,0,255),2);   
    //}
    //imwrite("模版图轮廓.jpg",img_template);
 
    double pro = 1;//相似度,越接近0越好
    double min_pro = 999;//对应的最优匹配值
    int min_kk = -1;//对应的最优匹配的下标
 
    for (int kk = 0; kk < contours_img.size(); kk++)
    {
        if (contourArea(contours_img[kk]) < 10000)//面积阈值筛选
        {
            break;
        }
        rt = boundingRect(contours_img[kk]);  
        if (rt.height <= rt.width)//垃圾桶是矩形
        {
            continue;
        }
 
        pro = matchShapes(contours_img[kk], contours_template[1], CV_CONTOURS_MATCH_I3, 1.0);//进行轮廓匹配
 
        if (pro < min_pro)
        {
            min_pro = pro;
            min_kk = kk;
        }
 
        cout << kk <<"=="<<pro<< endl;
    }
 
    rt = boundingRect(contours_img[min_kk]);
    rectangle(img, rt, Scalar(0,0,255),2);   
 
    cout << "相似度最高轮廓下标:"<<min_kk <<endl;
    cout << "目标形心坐标:"<<rt.x + rt.width/2<<","<<rt.y + rt.height/2<<endl;
 
    imwrite("目标寻找结果.jpg",img);
 
    return 0;
}

需要说明的是图1并不是从图2里抠出来的,是另外近距离拍摄的,直接用sift,surf效果并不是很好,但是轮廓形状却变化不大。上面的图我为了排版缩放了。图1、3大小2248*2248   图2、4、5大小3671*3627

 

示例2-1

    //轮廓发现(find contour)
    //轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现结果
    //步骤:输入图像转为灰度图像cvtColor
          //使用Canny进行边缘提取,得到二值图像
          //使用findContours寻找轮廓
          //使用drawContours绘制轮廓
     
    #include"stdafx.h"
    #include<opencv2/opencv.hpp>
    #include<iostream>
    #include<math.h>
     
    using namespace std;
    using namespace cv;
     
    Mat src, dst;
    char input[] = "gray image";
    int threshold_value = 100;
    int threshold_max = 255;
    void find_contour_demo(int, void*);
    int main(int argc, char*argv)
    {
        src = imread("C:\\Users\\59235\\Desktop\\imag\\mixed_03.png");
        if (!src.data)
        {
            printf("could not load image...\n");
            return -1;
        }
        namedWindow(input, CV_WINDOW_AUTOSIZE);
        namedWindow("result", CV_WINDOW_AUTOSIZE);
        //输入图像转为灰度图像
        cvtColor(src, src, CV_BGR2GRAY);
        imshow(input, src);
     
        const char*thresh = "threshold value";
        createTrackbar(thresh, input, &threshold_value, threshold_max, find_contour_demo);
        find_contour_demo(0, 0);
     
        waitKey(0);
        return 0;
    }
     
    void find_contour_demo(int, void*)
    {
        //使用Canny进行边缘提取,得到二值图像
        Canny(src, dst, threshold_value, threshold_value * 2, 3, false);
        imshow("canny detection", dst);
     
        //使用findContours寻找轮廓
        vector<vector<Point>> contours;
        vector<Vec4i> hierachy;
        findContours(dst, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
        //findContours(
        //InputOutputArray  binImg, // 输入图像,非0的像素被看成1,0的像素值保持不变,8-bit
        //OutputArrayOfArrays  contours,//  全部发现的轮廓对象
        //OutputArray, hierachy// 图该的拓扑结构,可选,该轮廓发现算法正是基于图像拓扑结构实现。
        //int mode, //  轮廓返回的模式
        //int method,// 发现方法
        //Point offset = Point()//  轮廓像素的位移,默认(0, 0)没有位移)
     
        //使用drawContours绘制轮廓
        Mat drawImage = Mat::zeros(src.size(), CV_8UC3);
        RNG rng(12345);
        for (int i = 0; i < contours.size(); i++)
        {
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            drawContours(drawImage, contours, i, color, 2, LINE_AA, hierachy, 0, Point(0, 0));
            //drawContours(
            //InputOutputArray  binImg, // 输出图像
            //OutputArrayOfArrays  contours,//  全部发现的轮廓对象
            //Int contourIdx// 轮廓索引号
            //const Scalar & color,// 绘制时候颜色
            //int  thickness,// 绘制线宽
            //int  lineType,// 线的类型LINE_8
            //InputArray hierarchy,// 拓扑结构图
            //int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓
            //Point offset = Point()// 轮廓位移,可选
        }
     
        imshow("result", drawImage);
        return;
    }

 

效果图:                        (灰度图)                                                                                                               (canny边缘检测图)

                                                                    (绘制轮廓图)

总结:OpenCV提取轮廓之后,还可以进行许多操作:

    ArcLength() 计算轮廓长度
    ContourArea() 计算轮廓区域的面积
    BoundingRect() 轮廓的外包矩形
    ConvexHull() 提取轮廓的凸包
    IsContourConvex() 测试轮廓的凸性
    MinAreaRect() 轮廓的最小外包矩形
    MinEnclosingCircle() 轮廓的最小外包圆
    fitEllipse()用椭圆拟合二维点集
    approxPolyDP()逼近多边形曲线

 

示例2-2

 //图像矩:(Image Moments)
    //步骤:提取图像边缘
    //发现轮廓
    //计算每个轮廓对象的矩
    //计算每个对象的中心、弧长、面积
     
    #include"stdafx.h"
    #include<opencv2/opencv.hpp>
    #include<iostream>
    #include<math.h>
     
    using namespace cv;
    using namespace std;
     
    Mat src, dst, drawImage;
    const char*result = "moments_demo";
    int threshold_value = 120;
    int threshold_max = 255;
    RNG rng(12345);
    void Moments_demo(int, void*);
    int main(int argc, char*argv)
    {
        src = imread("C:\\Users\\59235\\Desktop\\imag\\mixed_01.png");
        if (!src.data)
        {
            printf("could not load image...\n");
            return -1;
        }
        char input[] = "gray image";
        namedWindow(input, CV_WINDOW_AUTOSIZE);
        namedWindow(result, CV_WINDOW_AUTOSIZE);
        //输入图像转为灰度图像
        cvtColor(src, dst, CV_BGR2GRAY);
        GaussianBlur(dst, dst, Size(3, 3), 0, 0);
        imshow(input, dst);
     
        const char*thresh = "threshold value";
        createTrackbar(thresh, result, &threshold_value, threshold_max, Moments_demo);
        Moments_demo(0, 0);
     
        waitKey(0);
        return 0;
    }
     
    void Moments_demo(int, void*)
    {
        //提取图像边缘
        Mat canny_out;
        Canny(dst, canny_out, threshold_value, threshold_value * 2, 3, false);
        //imshow("canny image", canny_out);
     
        //发现轮廓,找到图像轮廓
        vector<vector<Point>> contours;
        vector<Vec4i> hierachy;
        findContours(canny_out, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
     
        //计算每个轮廓对象的矩
        vector<    Moments> contours_moments(contours.size());
        vector<Point2f> centers(contours.size());
        for (size_t i = 0; i < contours.size(); i++)
        {
            //计算矩
            contours_moments[i] = moments(contours[i]);
            //moments(InputArray  array,//输入数据
            //bool   binaryImage = false // 是否为二值图像
            centers[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));
            //图像中心Center(x0, y0)=(m10/m00,m01/m00)
        }
     
        src.copyTo(drawImage);
        for (size_t i = 0; i < contours.size(); i++)
        {
            printf("centers point x:%.2f,y:%.2f\n", centers[i].x, centers[i].y);
            printf("contours %d Area:%.2f Arc length:%.2f \n", i, contourArea(contours[i]), arcLength(contours[i], true));
            //contourArea(InputArray  contour,//输入轮廓数据
            //bool   oriented// 默认false、返回绝对值)
            //arcLength(InputArray  curve,//输入曲线数据
            //bool   closed// 是否是封闭曲线)
     
            //考虑如何把数据显示在原图像上
            //double A;
            //A=contourArea(contours[i]);
            //ostringstream os;
            //os << A;
            //putText(drawImage,os.str,centers[i], CV_FONT_BLACK, 2.0, Scalar(0,0,255), 2, 8);
            //依次含义:原图,输入字的内容,起始位置,字体,字的大小,颜色,线条大小粗 细,连接域
     
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            drawContours(drawImage, contours, i, color, 2, LINE_AA, hierachy, 0, Point(0, 0));//绘制轮廓
            circle(drawImage, centers[i], 2, color, 2, LINE_AA);//绘制图形中心
        }
        imshow(result, drawImage);
        return;
    }

效果图:

  • 32
    点赞
  • 197
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
OpenCV Sharp 是 .NET 平台上的 OpenCV 库,它提供了一系列图像处理和计算机视觉的函数。要实现轮廓匹配,可以使用 OpenCV Sharp 中的 `FindContours()` 和 `MatchShapes()` 函数。 首先,使用 `FindContours()` 函数找到两个图像中的轮廓。例如: ```csharp Mat img1 = new Mat("image1.png", ImreadModes.GrayScale); Mat img2 = new Mat("image2.png", ImreadModes.GrayScale); List<MatOfPoint> contours1 = new List<MatOfPoint>(); List<MatOfPoint> contours2 = new List<MatOfPoint>(); Mat hierarchy1 = new Mat(); Mat hierarchy2 = new Mat(); Cv2.FindContours(img1, contours1, hierarchy1, RetrievalModes.External, ContourApproximationModes.ApproxSimple); Cv2.FindContours(img2, contours2, hierarchy2, RetrievalModes.External, ContourApproximationModes.ApproxSimple); ``` 然后,对于每个图像中的轮廓,使用 `MatchShapes()` 函数计算它们之间的形状相似度。例如: ```csharp double minMatchValue = double.MaxValue; foreach (MatOfPoint contour1 in contours1) { foreach (MatOfPoint contour2 in contours2) { double matchValue = Cv2.MatchShapes(contour1, contour2, ShapeMatchModes.I2); if (matchValue < minMatchValue) minMatchValue = matchValue; } } Console.WriteLine("The minimum match value is: " + minMatchValue); ``` 在上面的代码中,我们使用了 `ShapeMatchModes.I2` 模式来计算形状相似度,这是一种较为通用的模式。输出的最小匹配值越小,表示两个图像中的轮廓越相似。 需要注意的是,这种轮廓匹配方法通常适用于形状简单的物体,对于形状复杂的物体,可能需要使用更为复杂的方法来进行匹配

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值