C# OpenCvSharp實(shí)現(xiàn)通過特征點(diǎn)匹配圖片
更新時間:2023年11月09日 10:37:01 作者:天天代碼碼天天
這篇文章主要為大家詳細(xì)介紹了C#如何結(jié)合OpenCVSharp4實(shí)現(xiàn)通過特征點(diǎn)匹配圖片,文中的示例代碼簡潔易懂,具有一定的學(xué)習(xí)價值,需要的小伙伴可以參考下
SIFT匹配

SURF匹配

項(xiàng)目

代碼
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對匹配的結(jié)果做過濾
var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
var outMask = new Mat();
// 如果原始的匹配結(jié)果為空, 則跳過過濾步驟
if (pSrc.Count > 0 && pDst.Count > 0)
Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
// 如果通過RANSAC處理后的匹配點(diǎn)大于10個,才應(yīng)用過濾. 否則使用原始的匹配點(diǎn)結(jié)果(匹配點(diǎn)過少的時候通過RANSAC處理后,可能會得到0個匹配點(diǎn)的結(jié)果).
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);
}
else
Cv2.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>();
//篩選較好的匹配點(diǎn)
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);
//距離小于范圍的壓入新的DMatch
goodMatches.Add(matches[i]);
}
}
var outMat = new Mat();
// 算法RANSAC對匹配的結(jié)果做過濾
var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
var outMask = new Mat();
// 如果原始的匹配結(jié)果為空, 則跳過過濾步驟
if (pSrc.Count > 0 && pDst.Count > 0)
Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
// 如果通過RANSAC處理后的匹配點(diǎn)大于10個,才應(yīng)用過濾. 否則使用原始的匹配點(diǎn)結(jié)果(匹配點(diǎn)過少的時候通過RANSAC處理后,可能會得到0個匹配點(diǎn)的結(jié)果).
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);
}
else
Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
return outMat;
}
}
}
}
}到此這篇關(guān)于C# OpenCvSharp實(shí)現(xiàn)通過特征點(diǎn)匹配圖片的文章就介紹到這了,更多相關(guān)C# OpenCvSharp匹配圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:
- C#中OpenCvSharp 通過特征點(diǎn)匹配圖片的方法
- C#中OpenCVSharp實(shí)現(xiàn)輪廓檢測
- C#安裝OpenCvSharp4的實(shí)現(xiàn)步驟
- C#借助OpenCvSharp讀取攝像頭并顯示的實(shí)現(xiàn)示例
- c#中WinForm用OpencvSharp實(shí)現(xiàn)ROI區(qū)域提取的示例
- c#中WinForm使用OpencvSharp4實(shí)現(xiàn)簡易抓邊
- C#結(jié)合OpenCVSharp4實(shí)現(xiàn)圖片相似度識別
- C#結(jié)合OpenCVSharp4使用直方圖算法實(shí)現(xiàn)圖片相似度比較
相關(guān)文章
c#實(shí)現(xiàn)數(shù)據(jù)庫事務(wù)示例分享
這篇文章主要介紹了c#執(zhí)行多條sql更新語句實(shí)現(xiàn)數(shù)據(jù)庫事務(wù)的示例,大家參考使用吧2014-01-01
C#編程簡單實(shí)現(xiàn)生成PDF文檔的方法示例
這篇文章主要介紹了C#編程簡單實(shí)現(xiàn)生成PDF文檔的方法,結(jié)合實(shí)例形式分析了C#生成PDF文檔的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-07-07
C#實(shí)現(xiàn)保存文件時重名自動生成新文件的方法
這篇文章主要介紹了C#實(shí)現(xiàn)保存文件時重名自動生成新文件的方法,涉及C#針對保存文件時出現(xiàn)重命名情況的自動處理技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07

