EmguCV (OpenCV) ORBDetector 仅发现不良匹配

2024-03-31

Problem

所以总的来说,我对计算机视觉还很陌生。我目前正在尝试通过分析 2 个图像来计算单应性。我想使用单应性来校正 1 个图像的视角以匹配另一个图像。但我得到的比赛却很糟糕而且错误。所以我所做的单应性扭曲完全关闭了。

当前状态

我正在使用 EmguCV 在 C# 中包装 opencv。 据我所知,我的代码似乎“正常”工作。

我加载两个图像并声明一些变量来存储计算工件。

(Image<Bgr, byte> Image, VectorOfKeyPoint Keypoints, Mat Descriptors) imgModel = (new Image<Bgr, byte>(imageFolder + "image0.jpg").Resize(0.2, Emgu.CV.CvEnum.Inter.Area), new VectorOfKeyPoint(), new Mat());
(Image<Bgr, byte> Image, VectorOfKeyPoint Keypoints, Mat Descriptors) imgTest = (new Image<Bgr, byte>(imageFolder + "image1.jpg").Resize(0.2, Emgu.CV.CvEnum.Inter.Area), new VectorOfKeyPoint(), new Mat());
Mat imgKeypointsModel = new Mat();
Mat imgKeypointsTest = new Mat();
Mat imgMatches = new Mat();
Mat imgWarped = new Mat();
VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch();
VectorOfVectorOfDMatch filteredMatches = new VectorOfVectorOfDMatch();
List<MDMatch[]> filteredMatchesList = new List<MDMatch[]>();

请注意,我使用ValueTuple<Image,VectorOfKeyPoint,Mat>直接存储图像及其各自的关键点和描述符。

之后使用 ORB 检测器和 BruteForce 匹配器来检测、描述和匹配关键点:

ORBDetector detector = new ORBDetector();
BFMatcher matcher = new BFMatcher(DistanceType.Hamming2);

detector.DetectAndCompute(imgModel.Image, null, imgModel.Keypoints, imgModel.Descriptors, false);
detector.DetectAndCompute(imgTest.Image, null, imgTest.Keypoints, imgTest.Descriptors, false);

matcher.Add(imgTest.Descriptors);
matcher.KnnMatch(imgModel.Descriptors, matches, k: 2, mask: null);

之后我应用比率测试 https://stackoverflow.com/questions/51197091/how-does-the-lowes-ratio-test-work并使用匹配距离阈值进行进一步的过滤。

MDMatch[][] matchesArray = matches.ToArrayOfArray();

//Apply ratio test
for (int i = 0; i < matchesArray.Length; i++)
{
  MDMatch first = matchesArray[i][0];
  float dist1 = matchesArray[i][0].Distance;
  float dist2 = matchesArray[i][1].Distance;

  if (dist1 < ms_MIN_RATIO * dist2)
  {
    filteredMatchesList.Add(matchesArray[i]);
  }
}

//Filter by threshold
MDMatch[][] defCopy = new MDMatch[filteredMatchesList.Count][];
filteredMatchesList.CopyTo(defCopy);
filteredMatchesList = new List<MDMatch[]>();

foreach (var item in defCopy)
{
  if (item[0].Distance < ms_MAX_DIST)
  {
    filteredMatchesList.Add(item);
  }
}

filteredMatches = new VectorOfVectorOfDMatch(filteredMatchesList.ToArray());

禁用任何这些过滤方法并不会真正使我的结果变得更好或更差(只是保留所有匹配项),但它们似乎有意义,所以我保留它们。

最后,我根据找到的和过滤的匹配计算我的单应性,然后用该单应性扭曲图像并绘制一些调试图像:

Mat homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(imgModel.Keypoints, imgTest.Keypoints, filteredMatches, null, 10);
CvInvoke.WarpPerspective(imgTest.Image, imgWarped, homography, imgTest.Image.Size);

Features2DToolbox.DrawKeypoints(imgModel.Image, imgModel.Keypoints, imgKeypointsModel, new Bgr(0, 0, 255));
Features2DToolbox.DrawKeypoints(imgTest.Image, imgTest.Keypoints, imgKeypointsTest, new Bgr(0, 0, 255));
Features2DToolbox.DrawMatches(imgModel.Image, imgModel.Keypoints, imgTest.Image, imgTest.Keypoints, filteredMatches, imgMatches, new MCvScalar(0, 255, 0), new MCvScalar(0, 0, 255));

//Task.Factory.StartNew(() => ImageViewer.Show(imgKeypointsModel, "Keypoints Model"));
//Task.Factory.StartNew(() => ImageViewer.Show(imgKeypointsTest, "Keypoints Test"));
Task.Factory.StartNew(() => ImageViewer.Show(imgMatches, "Matches"));
Task.Factory.StartNew(() => ImageViewer.Show(imgWarped, "Warp"));

tl;dr:ORBDetector->BFMatcher->FilterMatches->GetHomography->WarpPerspective

Output

Example for the algorithm Example for the algorithm

Test whether projection is going wrong Test whether projection is going wrong

Using crosscheck when matching Using crosscheck when matching

原始图像均为 2448x3264,缩放 0.2before对它们进行任何计算。

Question

基本上它既简单又复杂:我做错了什么? 正如您从上面的示例中看到的,我检测特征并匹配它们的方法似乎效果非常差。所以我问是否有人可以发现我的代码中的错误。或者给出建议,说明为什么我的结果如此糟糕,因为互联网上有数百个示例展示了它的工作原理以及它是多么“简单”。

到目前为止我尝试过的:

  • 输入图像的缩放。如果我将它们缩小很多,通常会得到更好的结果。
  • 检测更多或更少的特征。当前使用的默认值为 500。增加或减少这个数字并没有真正让我的结果更好。
  • k 的各种数字,但除 k = 2 之外的其他数字对我来说没有任何意义,因为我不知道如何修改 k > 2 的比率测试。
  • 改变过滤器参数,例如使用 0.6-0.9 的比率进行定量测试。
  • 使用不同的图片:二维码、恐龙剪影、我办公桌周围的一些其他随机物体。
  • 根据结果​​的任何变化改变重新投影阈值从 1 到 10
  • 验证投影本身没有问题。为模型和测试提供相同图像的算法会产生单应性并用单应性扭曲图像。图像不应改变。这按预期工作(参见示例图 2)。
  • 图 3:匹配时使用交叉检查。看起来更有希望,但仍然不是我所期待的。
  • 使用其他距离方法:Hamming、Hamming2、L2Sqr(不支持其他)

我使用的例子:

  • https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_matcher/py_matcher.html#matcher https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_matcher/py_matcher.html#matcher

  • https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html

  • https://www.learnopencv.com/image-alignment-feature-based-using-opencv-c-python/ https://www.learnopencv.com/image-alignment-feature-based-using-opencv-c-python/(我在那里得到了代码的主要结构)

原始图片:原始图像可以从这里下载:https://drive.google.com/open?id=1Nlqv_0sH8t1wiH5PG-ndMxoYhsUbFfkC https://drive.google.com/open?id=1Nlqv_0sH8t1wiH5PG-ndMxoYhsUbFfkC

自询问以来的进一步实验

So I did some further research after asking. Most changes are already included above but I wanted to make a separate section for this one. So after running into so many problems and seemingly nowhere to start I decided to google up the original paper on ORB http://www.willowgarage.com/sites/default/files/orb_final.pdf. After this I decided to try and replicate some of their results. Upon trying this I realised that even I try to match the match image rotate by a degree the matches seem to look fine but the transformation completely breaks down. Rotation

我尝试复制物体视角的方法是否有可能是错误的?

MCVE

https://drive.google.com/open?id=17DwFoSmco9UezHkON5prk8OsPalmp2MX https://drive.google.com/open?id=17DwFoSmco9UezHkON5prk8OsPalmp2MX(没有包,但 nuget Restore 足以让它编译)


我遇到了同样的问题并找到了合适的解决方案:github Emgu.CV.Example DrawMatches.cs https://github.com/emgucv/emgucv/blob/master/Emgu.CV.Example/FeatureMatching/DrawMatches.cs一切正常。

我修改了代码和方法FindMatch 看起来像这样:

public static void FindMatch(Mat modelImage, Mat observedImage, out VectorOfKeyPoint modelKeyPoints, out VectorOfKeyPoint observedKeyPoints, VectorOfVectorOfDMatch matches, out Mat mask, out Mat homography)
{
    int k = 2;
    double uniquenessThreshold = 0.80;
    homography = null;
    modelKeyPoints = new VectorOfKeyPoint();
    observedKeyPoints = new VectorOfKeyPoint();
    using (UMat uModelImage = modelImage.GetUMat(AccessType.Read))
    using (UMat uObservedImage = observedImage.GetUMat(AccessType.Read))
    {
        var featureDetector = new ORBDetector(9000);
        Mat modelDescriptors = new Mat();
        featureDetector.DetectAndCompute(uModelImage, null, modelKeyPoints, modelDescriptors, false);
        Mat observedDescriptors = new Mat();
        featureDetector.DetectAndCompute(uObservedImage, null, observedKeyPoints, observedDescriptors, false);
        using (var matcher = new BFMatcher(DistanceType.Hamming, false))
        {
            matcher.Add(modelDescriptors);

            matcher.KnnMatch(observedDescriptors, matches, k, null);
            mask = new Mat(matches.Size, 1, DepthType.Cv8U, 1);
            mask.SetTo(new MCvScalar(255));
            Features2DToolbox.VoteForUniqueness(matches, uniquenessThreshold, mask);

            int nonZeroCount = CvInvoke.CountNonZero(mask);
            if (nonZeroCount >= 4)
            {
                nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints,
                    matches, mask, 1.5, 20);
                if (nonZeroCount >= 4)
                    homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(modelKeyPoints,
                        observedKeyPoints, matches, mask, 2);
            }
        }
    }
}

Using:

var model = new Mat(@"image0.jpg");
var scene = new Mat(@"image1.jpg");
Mat result = new Mat();
VectorOfKeyPoint modelKeyPoints;
VectorOfKeyPoint observedKeyPoints;
var matches = new VectorOfVectorOfDMatch();
Mat mask;
Mat homography;
FindMatch(model, scene, out modelKeyPoints, out observedKeyPoints, matches, out mask, out homography);
CvInvoke.WarpPerspective(scene, result, homography, model.Size, Inter.Linear, Warp.InverseMap);

Result:

如果你想看过程使用下一个代码:

public static Mat Draw(Mat modelImage, Mat observedImage)
{
    Mat homography;
    VectorOfKeyPoint modelKeyPoints;
    VectorOfKeyPoint observedKeyPoints;
    using (VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch())
    {
        Mat mask;
        FindMatch(modelImage, observedImage, out modelKeyPoints, out observedKeyPoints, matches, out mask, out homography);
        Mat result = new Mat();
        Features2DToolbox.DrawMatches(modelImage, modelKeyPoints, observedImage, observedKeyPoints,
            matches, result, new MCvScalar(255, 0, 0), new MCvScalar(0, 0, 255), mask);

        if (homography != null)
        {
            var imgWarped = new Mat();
            CvInvoke.WarpPerspective(observedImage, imgWarped, homography, modelImage.Size, Inter.Linear, Warp.InverseMap);
            Rectangle rect = new Rectangle(Point.Empty, modelImage.Size);
            var pts = new PointF[]
            {
                  new PointF(rect.Left, rect.Bottom),
                  new PointF(rect.Right, rect.Bottom),
                  new PointF(rect.Right, rect.Top),
                  new PointF(rect.Left, rect.Top)
            };

            pts = CvInvoke.PerspectiveTransform(pts, homography);
            var points = new Point[pts.Length];
            for (int i = 0; i < points.Length; i++)
                points[i] = Point.Round(pts[i]);

            using (var vp = new VectorOfPoint(points))
            {
                CvInvoke.Polylines(result, vp, true, new MCvScalar(255, 0, 0, 255), 5);
            }
        }
        return result;
    }
}

Using:

var model = new Mat(@"image0.jpg");
var scene = new Mat(@"image1.jpg");
var result = Draw(model, scene);

Result:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

EmguCV (OpenCV) ORBDetector 仅发现不良匹配 的相关文章

  • 仅使用扩展方法在 Linq 中进行漂亮、干净的交叉连接 [重复]

    这个问题在这里已经有答案了 可能的重复 使用扩展方法表示的嵌套 from LINQ 查询 https stackoverflow com questions 9115675 nested from linq query expressed
  • C语言中的递归是如何工作的?

    我试图了解 C 中递归的工作原理 任何人都可以给我解释控制流吗 include
  • 如何使用 ILoggerFactory 记录 Polly 的重试

    或者 如何从静态方法记录 From https github com App vNext Polly https github com App vNext Polly你有这样的例子 其中记录器神奇地可用 Policy Timeout 30
  • MySql 最后插入 ID,连接器 .net

    我正在使用 MySql Connector net 我需要获取最后一个查询生成的插入 id 现在 我假设返回值是MySqlHelper ExecuteNonQuery应该是最后一个插入id 但它只返回1 我正在使用的代码是 int inse
  • 每次调用新方法时触发事件

    我正在做一个logger for a c 应用程序需要记录每个方法被调用的时间以及每个方法执行时间 我可以通过调用自己的方法来做到这一点EventLogger LogMethodCall方法在每个方法的开头 但我想知道是否有办法使CLR每次
  • 宏可以按参数数量重载吗?

    如何this https stackoverflow com q 9183993 153285工作 如何实现 C99 C 11 可变参数宏以仅根据为其提供多少个参数来扩展到不同的事物 编辑 请参阅末尾以获得现成的解决方案 要获得重载的宏 首
  • “包含字符串”的快速索引

    在我的应用程序中 我有多达数百万个短字符串 大部分短于 32 个字符 我想实现一个带有附加列表的搜索框 该列表仅包含包含在搜索框中输入的整个字符串的元素 如何预先建立索引来快速找到此类字符串 所有排序的 STL 容器都会检查整个字符串 对于
  • C++:将模板参数的模板类型成员添加为好友的正确语法?

    我有一个带有模板类型参数 tTRAIT 的类 我想加一个模板为好友type member aliastTRAIT 但我无法弄清楚语法 这可能吗 template
  • 如何使用boost库读取和写入.ini文件[重复]

    这个问题在这里已经有答案了 如何使用boost库读取和写入 或修改 ini文件 With Boost PropertyTree您可以读取并更新树 然后写入文件 请参阅load and save功能 看一下如何访问属性树中的数据 http w
  • 使用 QGraphicsScene 实现流畅的动画

    我希望我的问题并不总是同样的问题 我有一个 QGraphicsScene 它的项目是一些 QGraphicsPixmap 我用一个计时器来移动它们 每秒 SetX 10 我设置 10是因为窗口大100 使用这个解决方案我的动画不流畅 我想我
  • 将一个整数从 C 客户端发送到 Java 服务器

    我使用此代码将一个整数从我的 Java 客户端发送到我的 Java 服务器 int n rand nextInt 50 1 DataOutputStream dos new DataOutputStream socket getOutput
  • 按值返回的函数的返回语句中的初始化

    我的问题源于深入研究std move in return语句 例如以下示例 struct A A std cout lt lt Constructed lt lt this lt lt std endl A A noexcept std c
  • 只读有运行时开销吗?

    出于某种原因 我一直认为readonly字段有与其相关的开销 我认为这是 CLR 跟踪是否存在readonly字段是否已初始化 这里的开销是一些额外的内存使用量 用于跟踪状态以及分配值时的检查 也许我这么认为是因为我不知道readonly字
  • SQL参数化查询不显示结果

    我的 DataAcess 类中有以下函数 但它没有显示任何结果 我的代码如下 public List
  • char* argv[] 在 c/c++ 中如何工作? [复制]

    这个问题在这里已经有答案了 我知道它用于使用命令行中的参数 但我没有得到声明 字符 argv 它是否意味着指向 char 数组的指针 如果是的话为什么没有大小 如果不是动态数组 就不需要有大小吗 我做了一些研究 发现有人说它会衰减为 cha
  • 从 exit() 和 fork() 返回的结果奇怪地发生了位移

    我有一个 C 代码 有时会自行分叉 每个分叉都会执行一些操作 然后返回一个错误代码 目前 每个子进程返回其 ID 0 n void other int numero exit numero int main for int i 0 i lt
  • 参数数量在编译时确定的 Lambda 函数

    我想声明一个带有 N 个参数的 lambda 函数 其中 N 是模板参数 就像是 template
  • 为什么我不能对普通变量进行多态?

    我是一名Java程序员 最近开始学习C 我对某事感到困惑 据我了解 在 C 中 要实现多态行为 您必须使用指针或引用 例如 考虑一个类Shape与实施的方法getArea 它有几个子类 每个子类都以不同的方式重写 getArea 然后考虑以
  • 如何使用 xamarin 表单提示用户进行地理定位

    我正在 Xamarin Forms 应用程序中开发一个应用程序 需要请求地理位置权限 如果获得许可 它需要从设备获取地理位置数据 然后将地理位置坐标放入 Forecast io URL 我正在使用 James 的 Geolocator 插件
  • 类模板的 C++ 静态成员 - 链接器警告“多重定义”[重复]

    这个问题在这里已经有答案了 假设出于某种原因 我想要一个类模板 MyTemp 和一些静态数据成员 smDummyVar Mytemp h ifndef MY TEMP H define MY TEMP H template

随机推荐

  • 错误:“_UserObject”对象没有属性“预测”

    我正在构建一个针对数据序列进行机器学习的 ANN 模型 当我调用模型来验证测试数据时 出现错误 model Sequential model add Dense 8 activation tanh input dim 10 model ad
  • PowerShell 脚本问题运算符

    我尝试在部署更新的驱动程序之前使用 PowerShell 检测 Intel NIC 驱动程序 我对脚本进行了一些更改以进行故障排除 以确保捕获正确的驱动程序版本 并最终验证操作符的正确使用 我可能不是 Change DeployVersio
  • 如何迭代天数

    我有一个循环 days this 的代码来制作叶子 我希望列签到和签出出勤将自动填充 从开始日期开始 到结束日期结束 exp I input startdate 2012 11 08 01 30 00 enddate 2012 11 10
  • Javafx字体派生粗体

    我想为我的 javafx 应用程序动态更改 加载的 文本字体 所以我做了以下代码 Font font Font loadFont Fonts class getClassLoader getResource path font woff t
  • 将变量从 Symfony2 传递到 Angular 范围的最佳方法

    作为许多其他开发人员面临的常见场景 我们有一个基于 Symfony2 TWIG 的成熟应用程序 并且一些 html twig 模板因 jQuery 代码过多而难以维护 抛弃 jQuery 并使用 Angular 怎么样 假设我有一些关于 A
  • 如何覆盖 net core web api 中的 OnAuthorization?

    早些时候我在 asp net 中实现了类似的东西 public class Authentication AuthorizationFilterAttribute public override void OnAuthorization H
  • 需要使用 d3 geoPath.projection(null) 缩放已经投影的数据

    基于 d3 1 4 版 文档https github com d3 d3 geo blob master README md geoProjection https github com d3 d3 geo blob master READ
  • 如何在不使用 zip() 的情况下将不同类型的 Future 组合成一个 Future

    我想创造一个类型的未来Future Class1 Class2 Class3 从下面的代码 然而 我发现做到这一点的唯一方法是使用 zip 我发现这个解决方案很丑陋而且不是最佳的 谁能启发我 val v for a lt val f0 Fu
  • 如何把照片贴在墙上?

    有人成功地将图片发布到当前用户的墙上吗 这是行不通的 如果图片参数是现有的图片 url 则不会显示 我正在使用最新的 FB C SDK 5 0 8 Beta var args new Dictionary
  • 如何重新加载 vue 组件?

    我知道解决方案是像这样更新道具数据 this selectedContinent 但我想使用另一种解决方案 在我阅读了一些参考资料后 解决方案是 this forceUpdate 我尝试了一下 但不起作用 演示和完整代码如下 https j
  • 向 Google 仪表添加 % 符号

    我正在使用 Google 仪表 并且想在仪表中的值后面添加一个 符号 我的值显示良好 没有百分比符号 整数 0 100 但是当我开始尝试添加百分比符号时 事情变得不稳定 这是我尝试过的 Format the data to include
  • iPhone CoreText:查找子字符串的像素坐标

    这是 Twitter 应用程序的屏幕截图供参考 http screencast com t YmFmYmI4M http screencast com t YmFmYmI4M 我想要做的是将浮动弹出窗口放置在可以跨越多行的 NSAttrib
  • 如何在 Puppeteer 中选择 iframe 元素内的元素

    由于 ESPN 不提供 API 因此我尝试使用 Puppeteer 来抓取有关我的 Fantasy Football League 的数据 但是 由于登录表单嵌套在 iframe 元素中 我很难尝试使用 puppeteer 登录 我已经去了
  • Next12 中带有 Prisma 适配器的 NextAuth 凭证提供程序不执行任何操作

    我已经设置了我的Nextjs Next12 with NextAuth 凭证提供者并使用棱镜适配器将用户会话保留在数据库中 我跟着这个文档 https next auth js org adapters prisma来自 NextAuth
  • 求解混合互补模型时出错

    直接使用 PATH 求解器 我无法解决下面提出的问题 最初的问题来源于https prod sandia gov techlib noauth access control cgi 2015 155584 pdf https prod sa
  • 以良好的质量和内存效率缩小资源中的位图

    我想缩小 500x500px 资源以始终适合由屏幕宽度确定的特定尺寸 目前我使用 Android 开发者网站 高效加载大位图 http developer android com training displaying bitmaps lo
  • on_message() 和 @bot.command 问题

    当我有on message 在我的代码中 它会停止所有其他的 bot command来自工作的命令 我尝试过await bot process commands message 但这也行不通 这是我的代码 bot event command
  • SQL Server - PIVOT - 两列转换为行

    我在一个专栏中看到了很多关于 PIVOT 的问题 每个问题都比其他问题更复杂 但是 我找不到我需要的任何内容 老实说 我什至不知道pivot在这种情况下是否能帮助我 假设我的源表中有这些数据 SELECT 1 as RowId Random
  • 混淆 .fmt 行为与嵌套列表

    The docs https docs raku org routine fmt比如说fmt 返回一个字符串 其中列表中的每个元素都已根据以下格式进行格式化 format 第一个参数 并且每个元素由 separator 第二个论点 根据该描
  • EmguCV (OpenCV) ORBDetector 仅发现不良匹配

    Problem 所以总的来说 我对计算机视觉还很陌生 我目前正在尝试通过分析 2 个图像来计算单应性 我想使用单应性来校正 1 个图像的视角以匹配另一个图像 但我得到的比赛却很糟糕而且错误 所以我所做的单应性扭曲完全关闭了 当前状态 我正在