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下载
相关文章:
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…...
10个python爬虫入门实例
昨天带伙伴学习python爬虫,准备了几个简单的入门实例,涉及主要知识点: web是如何交互的 requests库的get、post函数的应用 response对象的相关函数,属性 python文件的打开,保存 代码中给出了注释,并且…...
麒麟KYLINOS命令行设置系统静音
原文链接:麒麟KYLINOS命令行设置系统静音 hello,大家好啊,今天给大家带来一篇在麒麟KYLINOS上使用命令行调节系统静音的方法,有时候需要制作模板,便可以采用此方法,话不多说,一起来看看吧。 1、…...
零信任安全:构建无懈可击的网络防护体系
随着网络技术的飞速发展,信息安全问题日益凸显,传统的安全防护手段已经无法满足复杂多变的安全需求。在此背景下,零信任安全模型逐渐受到广泛关注。本文将探讨零信任安全的概念、优势以及如何构建无懈可击的网络防护体系。 一、零信任安全概念…...
华为李鹏:到 2025 年智能算力需求将达到目前水平的 100 倍
在第十四届全球移动宽带论坛上,华为高级副总裁、运营商 BG 总裁李鹏表示,大模型为代表的 AI 应用发展带来对智能算力的爆发式需求。 李鹏在题为《加速 5G 商业正循环,拥抱更繁荣的 5.5G》的讲话中表示,「5G 已经走在商业成功的正确…...
【漏洞复现】深信服下一代防火墙NGAF存在任意文件上传漏洞 附POC
漏洞描述 深信服下一代防火墙(Next-Generation Application Firewall)NGAF是面向应用层设计,能够精确识别用户、应用和内容,具备完整安全防护能力,能够全面替代传统防火墙,并具有强劲应用层处理能力的全新网络安全设备。NGAF解决了传统安全设备在应用识别、访问控制、内…...
城市内涝积水预防,万宾科技内涝监测仪如何预警?
近几年来城市内涝所引发的安全隐患极为突出,影响着城市道路安全,而且也让市民心中多有惶恐。一旦城市内涝问题出现背后不仅是路面积水问题,更会导致城市无法正常运行,导致市民日常生活和工作受到影响。所以对于排水防涝设施的建设…...
SpringBoot定时任务打成jar 引入到新的项目中后并自动执行
一、springBoot开发定时任务 ①:连接数据库实现新增功能 1. 引入依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional> </dependency> <dependen…...
AD9371 官方例程 NO-OS 主函数 headless 梳理(一)
AD9371 系列快速入口 AD9371ZCU102 移植到 ZCU106 : AD9371 官方例程构建及单音信号收发 ad9371_tx_jesd -->util_ad9371_xcvr接口映射: AD9371 官方例程之 tx_jesd 与 xcvr接口映射 AD9371 官方例程 时钟间的关系与生成 : AD9371 官方…...
SHAP 和 LIME 解释模型
内容大纲 1、SHAP 解释器1.1 案例:用于预测患者肺癌1.2 案例中使用的shap解释器1.3 SHAP工作原理1.4 举例说明 2、LIME 解释器2.1 案例:判断法律案件胜诉可能性2.2 LIME解释器工作原理2.3 本地解释模型的训练过程2.4 举例说明1:新闻分类2.4 举…...
若依vue-初步下载使用
若依框架可以满足大部分的后台管理系统的开发,使用频率也是比较高的,所以这里讲一下如何使用若依框架 若依框架代码克隆 首先去若依官网 http://www.ruoyi.vip/ 这里演示的是若依-vue版本的使用 我们点击下载 会跳转到码云仓库 或者直接点击下面的链接去码云仓库 https://git…...
Android 使用.9图 NinePatchDrawable实现动态聊天气泡
最近一段时间,在做一个需求,需要实现一个聊天气泡的动画效果,如下图所示: GitHub源码demo ,建议下载demo,运行查看。 动态聊天气泡动画 静态聊天气泡 经过一段时间调研,实现方案如下: 实现方…...
力扣 LCR 024. 反转链表两种解法
目录 1.解题思路Ⅰ2.代码实现Ⅰ3.解题思路Ⅱ4.代码实现Ⅱ 1.解题思路Ⅰ 利用头插法,遍历数组将后面的元素头插到前面的元素. 2.代码实现Ⅰ struct ListNode* reverseList(struct ListNode* head) { struct ListNode*curhead;;struct ListNode*newheadNULL;whil…...
掌握Capture One 23 Pro,打造专业级图片编辑体验!
作为一位摄影师,您是否曾经为自己的照片无法达到预期效果而烦恼?或者您是否在寻找一种能够让您轻松处理和编辑照片的工具?如果是,那么您一定不能错过Capture One 23 Pro这款图片编辑软件! Capture One 23 Pro的特点 …...
MFC-TCP网络编程服务端-Socket
目录 1、通过Socket建立服务端: 2、UI设计: 3、代码的实现: (1)、CListenSocket类 (2)、CConnectSocket类 (3)、CTcpServerDlg类 1、通过Socket建立服务端ÿ…...
ChatGPT辅助下的小组学习
1 网上分享会-主题 1.9曾子曰:“慎终追远,民德归厚矣。” Master Zeng said:“Be circumspect in funerary services and continue sacrifices to the distant ancestors, and the virtue (de 德) of the common people will thrive.” 2 过程记录 听…...
Linux相关命令
切换root用户:sudo su 串口功能测试:cutecom 某某驱动查询:nvidia-smi #xxx-smi查询某某驱动 在线安装某某程序:apt install xxx 设置文件权限chmod 常用:chmod 777 sudo chmod 600 (只有所有者…...
详解卷积神经网络结构
前言 卷积神经网络是以卷积层为主的深度网路结构,网络结构包括有卷积层、激活层、BN层、池化层、FC层、损失层等。卷积操作是对图像和滤波矩阵做内积(元素相乘再求和)的操作。 1. 卷积层 常见的卷积操作如下: 卷积操作解释图解…...
java读取pdf数据
目录 读取方式有两种: 方式一: 方式一所需要的maven依赖如下: 方式一读取的Java代码如下:<...
arcmap / arcgis 安装教程
ArcGIS 10.8 for Desktop 完整安装教程(含win7/8/10 32/64位下载地址亲测可用汉化) | 麻辣GIS (malagis.com) 关于GIS语言汉化包(中文)安装失败的解决办法_arcgis中文语言包_miumiuniya的博客-CSDN博客 检查安装路径:…...
医疗影像不平衡分类实战:乳腺X光微钙化检测
1. 乳腺X光微钙化检测的不平衡分类模型构建实战作为一名在医疗影像分析领域工作多年的数据科学家,我经常遇到像乳腺X光微钙化检测这样的极端不平衡分类问题。今天我将分享如何构建一个高性能的检测模型,这个项目基于经典的Woods Mammography数据集&#…...
保姆级教程:用mxbai-embed-large-v1快速搭建文本检索系统,零基础也能上手
保姆级教程:用mxbai-embed-large-v1快速搭建文本检索系统,零基础也能上手 1. 项目简介与核心价值 mxbai-embed-large-v1是一款强大的文本嵌入模型,能够将文本转换为高维向量表示。它在MTEB基准测试中表现优异,超越了包括OpenAI在…...
Qwen3-4B-Thinking-2507-Gemini-2.5-Flash-Distill多语言支持实测
Qwen3-4B-Thinking-2507-Gemini-2.5-Flash-Distill多语言支持实测 1. 模型简介与背景 Qwen3-4B-Thinking-2507-Gemini-2.5-Flash-Distill是一个基于vLLM框架部署的文本生成模型,通过Chainlit前端提供交互式体验。该模型在约5440万个由Gemini 2.5 Flash生成的token…...
省钱又解压!24小时自助洗车,解锁车主休闲新方式!
谁说洗车只能是一项枯燥的家务?如今,越来越多车主爱上24小时自助洗车,不仅是因为它便捷实 惠,更因为它成为了当下热门的低成本解压方式,让洗车从单纯的清洁任务,变成了放松身心的休闲时光。 当代年轻人生活…...
MGRE综合实验报告册
实验要求:1,R5为ISP,只能进行IP地址配置,其所有地址均配为公有IP地址;2,R1和R5间使用PPP的PAP认证,R5为主认证方;R2与R5之间使用ppp的CHAP认证,R5为主认证方; R3与R5之间使用HDLC封装…...
【实测避坑】英文论文降AI:5大工具红黑榜与底层精修逻辑
留学生降ai成了一个大难题,很多同学都在问怎么给英文降ai,外文导师对AI查得非常严,如果turnitin检测ai率太高就麻烦了。 我也试过网上一大堆免费降ai率工具,踩了一大堆坑,今天不说虚的,给大家分享一下我的…...
Proxmox VE模板制作实战:将Ubuntu 22.04 Cloud-Init镜像打造成你的“黄金镜像”
Proxmox VE黄金镜像实战:从Ubuntu 22.04 Cloud-Init到企业级模板的深度优化 在虚拟化环境中,标准化镜像的管理效率直接决定了运维团队的生产力水平。想象一下这样的场景:凌晨三点收到业务扩容需求,你需要快速部署20台配置一致的Ub…...
Spring Cloud Gateway与Vite开发模式的协同工作
引言 在现代Web开发中,前端和后端的解耦使得开发变得更加灵活和高效。Spring Cloud Gateway作为一个强大的API网关,可以有效地管理微服务间的请求路由。然而,当前端应用使用Vite进行开发时,可能会遇到一些路由和请求转发的问题。今天我们来探讨如何解决Spring Cloud Gatew…...
第88篇:AI+环境保护与气候研究——污染监测、物种识别与气候建模(项目实战)
文章目录项目背景技术选型架构设计核心实现1. 黑烟车识别 (基于YOLOv8)2. PM2.5浓度时序预测 (基于Informer)踩坑记录效果对比项目背景 这几年做AI项目,从互联网卷到传统行业,一个很深的感触是:AI技术真正产生巨大价值的,往往是那…...
minimax_image插件基本上能做到无AI感出图了
minimax_image插件介绍minimax_image插件能够通过调用minimax模型生成图像,注意:使用时需要提供minimax的 api key (api 密钥)和 group id (组id)。如何安装 minimax_image 插件步骤 1:进入工具市场在 InfiniSynapse (网页版&…...
