C# OpenCvSharp 通过特征点匹配图片

SIFT匹配

SURF匹配

项目

代码

using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;namespace OpenCvSharp_Demo
{public partial class frmMain : Form{public frmMain(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){}private void button2_Click(object sender, EventArgs e){Mat matSrc = new Mat("1.jpg");Mat matTo = new Mat("2.jpg");var outMat = MatchPicBySift(matSrc, matTo);pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat);}private void button1_Click(object sender, EventArgs e){Mat matSrc = new Mat("1.jpg");Mat matTo = new Mat("2.jpg");var outMat = MatchPicBySurf(matSrc, matTo, 10);pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat);}public Point2d Point2fToPoint2d(Point2f point) => new Point2d((double)point.X, (double)point.Y);public Mat MatchPicBySift(Mat matSrc, Mat matTo){using (Mat matSrcRet = new Mat())using (Mat matToRet = new Mat()){KeyPoint[] keyPointsSrc, keyPointsTo;using (var sift = OpenCvSharp.Features2D.SIFT.Create()){sift.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);sift.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);}using (var bfMatcher = new OpenCvSharp.BFMatcher()){var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);var pointsSrc = new List<Point2f>();var pointsDst = new List<Point2f>();var goodMatches = new List<DMatch>();foreach (DMatch[] items in matches.Where(x => x.Length > 1)){if (items[0].Distance < 0.5 * items[1].Distance){pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);goodMatches.Add(items[0]);Console.WriteLine($"{keyPointsSrc[items[0].QueryIdx].Pt.X}, {keyPointsSrc[items[0].QueryIdx].Pt.Y}");}}var outMat = new Mat();// 算法RANSAC对匹配的结果做过滤var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);var pDst = pointsDst.ConvertAll(Point2fToPoint2d);var outMask = new Mat();// 如果原始的匹配结果为空, 则跳过过滤步骤if (pSrc.Count > 0 && pDst.Count > 0)Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);// 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).if (outMask.Rows > 10){byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];outMask.GetArray(out maskBytes);Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);}elseCv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);return outMat;}}}public Mat MatchPicBySurf(Mat matSrc, Mat matTo, double threshold = 400){using (Mat matSrcRet = new Mat())using (Mat matToRet = new Mat()){KeyPoint[] keyPointsSrc, keyPointsTo;using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(threshold, 4, 3, true, true)){surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);}using (var flnMatcher = new OpenCvSharp.FlannBasedMatcher()){var matches = flnMatcher.Match(matSrcRet, matToRet);//求最小最大距离double minDistance = 1000;//反向逼近double maxDistance = 0;for (int i = 0; i < matSrcRet.Rows; i++){double distance = matches[i].Distance;if (distance > maxDistance){maxDistance = distance;}if (distance < minDistance){minDistance = distance;}}Console.WriteLine($"max distance : {maxDistance}");Console.WriteLine($"min distance : {minDistance}");var pointsSrc = new List<Point2f>();var pointsDst = new List<Point2f>();//筛选较好的匹配点var goodMatches = new List<DMatch>();for (int i = 0; i < matSrcRet.Rows; i++){double distance = matches[i].Distance;if (distance < Math.Max(minDistance * 2, 0.02)){pointsSrc.Add(keyPointsSrc[matches[i].QueryIdx].Pt);pointsDst.Add(keyPointsTo[matches[i].TrainIdx].Pt);//距离小于范围的压入新的DMatchgoodMatches.Add(matches[i]);}}var outMat = new Mat();// 算法RANSAC对匹配的结果做过滤var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);var pDst = pointsDst.ConvertAll(Point2fToPoint2d);var outMask = new Mat();// 如果原始的匹配结果为空, 则跳过过滤步骤if (pSrc.Count > 0 && pDst.Count > 0)Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);// 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).if (outMask.Rows > 10){byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];outMask.GetArray(out maskBytes);Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);}elseCv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);return outMat;}}}}
}

下载

Demo下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/135630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业防范数据安全的重要性与策略

随着信息技术的快速发展&#xff0c;企业的数据安全问题日益凸显。数据安全不仅关乎企业的商业机密&#xff0c;还涉及到客户的隐私和信任。因此&#xff0c;企业必须采取有效的防范措施&#xff0c;确保数据安全。本文将探讨企业防范数据安全的重要性&#xff0c;并介绍一些实…

【ARM Coresight OpenOCD 系列 1 -- OpenOCD 介绍】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 文章目录 1.1 OpenOCD 介绍1.1.1 OpenOCD 支持的JTAG 适配器1.1.2 OpenOCD 支持的调试设备1.1.3 OpenOCD 支持的 Flash 驱动 1.2 OpenOCD 安装与使用1.2.1 OpenOCD 代码获取及安装1.2.2 OpenOCD 使用1.2.3 OpenOCD 启用 GDB…

Vim基本使用操作

前言&#xff1a;作者也是初学Linux&#xff0c;可能总结的还不是很到位 Linux修炼功法&#xff1a;初阶功法 ♈️今日夜电波&#xff1a;美人鱼—林俊杰 0:21━━━━━━️&#x1f49f;──────── 4:14 …

9 网关的作用

1、总结&#xff1a; 1.如果离开本局域网&#xff0c;就需要经过网关&#xff0c;网关是路由器的一个网口。 2.路由器是一个三层设备&#xff0c;里面有如何寻找下一跳的规则 3.经过路由器之后 MAC 头要变&#xff0c;如果 IP 不变&#xff0c;相当于不换护照的欧洲旅游&#…

Java中对象转型

理解&#xff1a; 有一个对象 new ADHero(), 同时也有一个引用ad 对象是有类型的&#xff0c; 是ADHero 引用也是有类型的&#xff0c;是ADHero 一般来说引用类型和对象类型是一样的&#xff0c;当引用类型和对象类型不一致就要考虑类型转换 简单判断&#xff1a;把右边的当…

查询优化器:RBO与CBO

SQL查询优化器 1、数据库系统发展简史2、SQL查询优化器3、查询优化器分类4、查询优化器执行过程5、CBO框架Calcite简介 1、数据库系统发展简史 数据库系统诞生于20世纪60年代中期&#xff0c;至今已有近50多年的历史&#xff0c;其发展经历了三代演变&#xff0c;造就了四位图灵…

如何更改IP地址为美国IP?美国静态住宅代理如何搭建?

相信很多做跨境电商或外贸如TikTok shop、Facebook商店、Amazon、领英的玩家都需要搭建独享的美国IP环境来运营店铺&#xff0c;那么如何搭建稳定独享的IP环境呢&#xff1f;加下来为你详细介绍&#xff0c;助力您的跨境业务。 一、选择合适的代理IP 代理IP可以帮助隐藏用户真…

RT-Thread 11. Scons 选择不同的编译器编译BSP

1.使用gcc编译工程&#xff0c;生成elf、bin文件 如果是 ARM 平台的芯片&#xff0c;则可以使用 Env 工具&#xff0c;输入 scons 命令直接编译 BSP&#xff0c;这时候默认使用的是 ARM GCC 编译器&#xff0c;因为 Env 工具带有 ARM GCC 编译器。 2.使用template.uvproj 生成…

Java 萌新入门 -- 一些常见的基础知识点

文章目录 前言第一章.java语言概述java语言基础1.程序文档风格和注释2.从键盘读取数据3.变量与赋值4.java标识符5.关于数据类型与逻辑运算符6.限制输出 小数位数&#xff1a;&#xff08;用第三种&#xff09;7.关于带标签的的循环控制语句 第二章.类和对象与数组的定义1.方法设…

搭建嵌入式GDB调试环境以及VSCode+gdbserver 图形化调试

目录 1 搭建嵌入式gdb调试环境 1.1 交叉编译工具链自带的gdb和gdbserver 1.2 使用gdb进行嵌入式程序调试 1.2.1编写简单测试程序 1.2.2 gdb调试程序 1.3 源码编译gdb和gdbserver 1.3.1 下载gdb和gdbserver源码 1.3.2 编译gdb 1.3.3 移植gdbserver 2 VSCodegdbserver 图…

单片机程序无法下载?

原因一&#xff1a;电源问题 电源可能是导致STM32微控制器无法下载程序的一个常见原因。确保电源稳定对于正常运行和下载程序至关重要。以下是一些电源问题&#xff1a; 1. 电源电压不足&#xff1a;如果STM32微控制器没有足够的电压供应&#xff0c;它可能无法正常工作或下载程…

22款奔驰GLS450升级中规主机 实现导航地图 中文您好奔驰

很多平行进口的奔驰GLS都有这么一个问题&#xff0c;原车的地图在国内定位不了&#xff0c;语音交互功能也识别不了中文&#xff0c;原厂记录仪也减少了&#xff0c;使用起来也是很不方便的。星骏汇小许 Xjh15863 其实很简单&#xff0c;我们只需要更换一台中规的新主机就可以实…

【数据结构】树与二叉树(六):二叉树的链式存储

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语5.1.4 树的表示 5.2 二叉树5.2.1 二叉树1. 定义2. 特点3. 性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉…

『MySQL快速上手』-⑤-数据类型

文章目录 1.数据类型有哪些2.数值类型2.1 tinyint 类型2.2 bit 类型2.3 小数类型2.3.1 float2.3.2 decimal 3.字符串类型3.1 char3.2 varchar3.2 char 和 varchar 比较 4.日期和时间类型5.enum和set 1.数据类型有哪些 MySQL支持多种数据类型&#xff0c;这些数据类型可用于定义…

【AntDesign】Docker部署

docker部署是主流的部署方式&#xff0c;极大的方便了开发部署环境&#xff0c;保持了环境的统一&#xff0c;也是实现自动化部署的前提。 1 项目的目录结构 dist: 使用build打包命令&#xff0c;生成的打包目录 npm run build : 打包项目命令 docker: 存放docker容器需要修改…

Python爬虫-获取汽车之家车家号

前言 本文是该专栏的第9篇,后面会持续分享python爬虫案例干货,记得关注。 地址:aHR0cHM6Ly9jaGVqaWFoYW8uYXV0b2hvbWUuY29tLmNuL0F1dGhvcnMjcHZhcmVhaWQ9MjgwODEwNA== 需求:获取汽车之家车家号数据 笔者将在正文中介绍详细的思路以及采集方法,废话不多说,跟着笔者直接往…

MCU系统的调试技巧

MCU系统的调试技巧对于确保系统稳定性和性能至关重要。无论是在嵌入式系统开发的初期阶段还是在产品维护和优化的过程中&#xff0c;有效的调试技巧可以帮助开发人员快速发现和解决问题&#xff0c;本文将讨论一些MCU系统调试的技巧。 首先&#xff0c;使用调试工具是非常重要…

[量化投资-学习笔记008]Python+TDengine从零开始搭建量化分析平台-CCI和ATR

目录 1. 指标简介CCIATR 2. 程序编写题外话 1. 指标简介 将这两个指标放在一起&#xff0c;一方面是因为这两个指标都属于摆动指数&#xff0c;可以反应市场的活跃度。 另一方面是因为CCI和ATR与之前提到的EMA,MACD,布林带的三个指标的计算基础不同。之前的三个指标都是以收盘…

AR眼镜硬件解决方案_AR/VR智能眼镜安卓主板芯片方案介绍

随着近两年来增强现实(AR)技术的逐渐成熟&#xff0c;采用MT8788芯片解决方案的AR眼镜已经问世。众所周知&#xff0c;AR技术可以帮助开发者打造一个既强大而又实用的混合现实世界&#xff0c;将虚拟与真实世界相结合。 据了解&#xff0c;MT8788芯片采用了多芯片分布式处理系统…

虚幻5.3打包Windows失败

缺失UnrealGame二进制文件。 必须使用集成开发环境编译该UE项目。或者借助虚幻编译工具使用命令行命令进行编译 解决办法&#xff1a; 1.依次点击平台-项目启动程序 2.点击后面的按钮进行设置 3.稍等后&#xff0c;打包后的程序即可运行&#xff0c;之后就可以愉快的打包了