emgucv:C# 中的 pan 卡不正确的倾斜检测

2024-02-22

我有三个泛卡图像,用于使用 emgucv 和 c# 测试图像的倾斜。

顶部的第一张图像检测到 180 度工作正常。

中间的第二张图像检测到的 90 度应检测为 180 度。

第三张图像检测到 180 度应检测为 90 度。

我想在这里分享的一个观察结果是,当我使用画笔从平移卡的上下侧裁剪图像的不需要的部分时,它使用下面提到的代码给了我预期的结果。

现在我想了解如何使用编程删除不需要的部分。 我玩过轮廓和投资回报率,但我不知道如何适应它们。我无法理解 emgucv 本身是否选择轮廓或者我必须做些什么。

请建议任何合适的代码示例。

请检查下面的代码以进行角度检测,请帮助我。提前致谢。

imgInput = new Image<Bgr, byte>(impath);
          Image<Gray, Byte> img2 = imgInput.Convert<Gray, Byte>();
          Bitmap imgs;
          Image<Gray, byte> imgout = imgInput.Convert<Gray, byte>().Not().ThresholdBinary(new Gray(50), new Gray(125));
          VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
          Emgu.CV.Mat hier = new Emgu.CV.Mat();
          var blurredImage = imgInput.SmoothGaussian(5, 5, 0 , 0);
          CvInvoke.AdaptiveThreshold(imgout, imgout, 255, Emgu.CV.CvEnum.AdaptiveThresholdType.GaussianC, Emgu.CV.CvEnum.ThresholdType.Binary, 5, 45);

          CvInvoke.FindContours(imgout, contours, hier, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
          if (contours.Size >= 1)
          {
              for (int i = 0; i <= contours.Size; i++)
              {

                  Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
                  RotatedRect box = CvInvoke.MinAreaRect(contours[i]);
                  PointF[] Vertices = box.GetVertices();
                  PointF point = box.Center;
                  PointF edge1 = new PointF(Vertices[1].X - Vertices[0].X, Vertices[1].Y - Vertices[0].Y);
                  PointF edge2 = new PointF(Vertices[2].X - Vertices[1].X, Vertices[2].Y - Vertices[1].Y);
                  double r = edge1.X + edge1.Y;
                  double edge1Magnitude = Math.Sqrt(Math.Pow(edge1.X, 2) + Math.Pow(edge1.Y, 2));
                  double edge2Magnitude = Math.Sqrt(Math.Pow(edge2.X, 2) + Math.Pow(edge2.Y, 2));
                  PointF primaryEdge = edge1Magnitude > edge2Magnitude ? edge1 : edge2;
                  double primaryMagnitude = edge1Magnitude > edge2Magnitude ? edge1Magnitude : edge2Magnitude;
                  PointF reference = new PointF(1, 0);
                  double refMagnitude = 1;
                  double thetaRads = Math.Acos(((primaryEdge.X * reference.X) + (primaryEdge.Y * reference.Y)) / (primaryMagnitude * refMagnitude));
                  double thetaDeg = thetaRads * 180 / Math.PI;
                  imgInput = imgInput.Rotate(thetaDeg, new Bgr());
                  imgout = imgout.Rotate(box.Angle, new Gray());
                  Bitmap bmp = imgout.Bitmap;
                  break;
              }

          }

问题

在解决问题之前,我们先从问题开始:

你的代码

当您提交代码、寻求帮助时,至少要努力“清理”它。帮助别人帮助你!这里有很多行代码什么也没做。您声明从未使用过的变量。添加一些注释,让人们知道您认为您的代码应该做什么。

Bitmap imgs;
var blurredImage = imgInput.SmoothGaussian(5, 5, 0, 0);
Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
PointF point = box.Center;
double r = edge1.X + edge1.Y;
// Etc

自适应阈值

以下代码行生成以下图像:

 CvInvoke.AdaptiveThreshold(imgout, imgout, 255, Emgu.CV.CvEnum.AdaptiveThresholdType.GaussianC, Emgu.CV.CvEnum.ThresholdType.Binary, 5, 45);

Image 1

Image 2

Image 3

显然这不是您的目标,因为主要轮廓(卡片边缘)完全丢失。作为提示,您始终可以使用以下代码在运行时显示图像以帮助您进行调试。

CvInvoke.NamedWindow("Output");
CvInvoke.Imshow("Output", imgout);
CvInvoke.WaitKey();

解决方案

由于您的示例图像中的卡片主要是与背景相似的值(在 HSV 意义上)。在这种情况下,我认为简单的灰度阈值处理不是正确的方法。我的目的如下:

算法

  1. 使用 Canny 边缘检测来提取图像中的边缘。

  2. 扩大边缘,使卡片内容结合在一起。

  3. 使用轮廓检测​​来过滤具有最大边界的组合边缘。

  4. 用旋转的矩形拟合该主轮廓以提取角点。

  5. 使用角点定义要应用的变换矩阵WarpAffine.

  6. 扭曲和裁剪图像。

The Code

您可能希望尝试一下 Canny 检测和扩张的参数。

// Working Images
Image<Bgr, byte> imgInput = new Image<Bgr, byte>("Test1.jpg");
Image<Gray, byte> imgEdges = new Image<Gray, byte>(imgInput.Size);
Image<Gray, byte> imgDilatedEdges = new Image<Gray, byte>(imgInput.Size);
Image<Bgr, byte> imgOutput;

// 1. Edge Detection
CvInvoke.Canny(imgInput, imgEdges, 25, 80);

// 2. Dilation
CvInvoke.Dilate(
    imgEdges,
    imgDilatedEdges,
    CvInvoke.GetStructuringElement(
        ElementShape.Rectangle,
        new Size(3, 3),
        new Point(-1, -1)),
    new Point(-1, -1),
    5,
    BorderType.Default,
    new MCvScalar(0));

// 3. Contours Detection
VectorOfVectorOfPoint inputContours = new VectorOfVectorOfPoint();
Mat hierarchy = new Mat();
CvInvoke.FindContours(
    imgDilatedEdges,
    inputContours,
    hierarchy,
    RetrType.External,
    ChainApproxMethod.ChainApproxSimple);
VectorOfPoint primaryContour = (from contour in inputContours.ToList()
                                orderby contour.GetArea() descending
                                select contour).FirstOrDefault();

// 4. Corner Point Extraction
RotatedRect bounding = CvInvoke.MinAreaRect(primaryContour);
PointF topLeft = (from point in bounding.GetVertices()
                  orderby Math.Sqrt(Math.Pow(point.X, 2) + Math.Pow(point.Y, 2))
                  select point).FirstOrDefault();
PointF topRight = (from point in bounding.GetVertices()
                  orderby Math.Sqrt(Math.Pow(imgInput.Width - point.X, 2) + Math.Pow(point.Y, 2))
                  select point).FirstOrDefault();
PointF botLeft = (from point in bounding.GetVertices()
                  orderby Math.Sqrt(Math.Pow(point.X, 2) + Math.Pow(imgInput.Height - point.Y, 2))
                  select point).FirstOrDefault();
PointF botRight = (from point in bounding.GetVertices()
                   orderby Math.Sqrt(Math.Pow(imgInput.Width - point.X, 2) + Math.Pow(imgInput.Height - point.Y, 2))
                   select point).FirstOrDefault();
double boundingWidth = Math.Sqrt(Math.Pow(topRight.X - topLeft.X, 2) + Math.Pow(topRight.Y - topLeft.Y, 2));
double boundingHeight = Math.Sqrt(Math.Pow(botLeft.X - topLeft.X, 2) + Math.Pow(botLeft.Y - topLeft.Y, 2));
bool isLandscape = boundingWidth > boundingHeight;

// 5. Define warp crieria as triangles              
PointF[] srcTriangle = new PointF[3];
PointF[] dstTriangle = new PointF[3];
Rectangle ROI;
if (isLandscape)
{
    srcTriangle[0] = botLeft;
    srcTriangle[1] = topLeft;
    srcTriangle[2] = topRight;
    dstTriangle[0] = new PointF(0, (float)boundingHeight);
    dstTriangle[1] = new PointF(0, 0);
    dstTriangle[2] = new PointF((float)boundingWidth, 0);
    ROI = new Rectangle(0, 0, (int)boundingWidth, (int)boundingHeight);
}
else
{
    srcTriangle[0] = topLeft;
    srcTriangle[1] = topRight;
    srcTriangle[2] = botRight;
    dstTriangle[0] = new PointF(0, (float)boundingWidth);
    dstTriangle[1] = new PointF(0, 0);
    dstTriangle[2] = new PointF((float)boundingHeight, 0);
    ROI = new Rectangle(0, 0, (int)boundingHeight, (int)boundingWidth);
}
Mat warpMat = new Mat(2, 3, DepthType.Cv32F, 1);
warpMat = CvInvoke.GetAffineTransform(srcTriangle, dstTriangle);

// 6. Apply the warp and crop
CvInvoke.WarpAffine(imgInput, imgInput, warpMat, imgInput.Size);
imgOutput = imgInput.Copy(ROI);
imgOutput.Save("Output1.bmp");

使用两种扩展方法:

static List<VectorOfPoint> ToList(this VectorOfVectorOfPoint vectorOfVectorOfPoint)
{
    List<VectorOfPoint> result = new List<VectorOfPoint>();
    for (int contour = 0; contour < vectorOfVectorOfPoint.Size; contour++)
    {
        result.Add(vectorOfVectorOfPoint[contour]);
    }
    return result;
}

static double GetArea(this VectorOfPoint contour)
{
    RotatedRect bounding = CvInvoke.MinAreaRect(contour);
    return bounding.Size.Width * bounding.Size.Height;
}

Outputs

元示例

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

emgucv:C# 中的 pan 卡不正确的倾斜检测 的相关文章

  • Linux 使用 boost asio 拒绝套接字绑定权限

    我在绑定套接字时遇到问题 并且以用户身份运行程序时权限被拒绝 这行代码会产生错误 acceptor new boost asio ip tcp acceptor io boost asio ip tcp endpoint boost asi
  • WP8.1 C# 绑定联系人图像

    信息很简单 我正在尝试创建一个可以显示用户联系人的应用程序 我也是一名自学成才的程序员 所以我在某些方面有编程经验 但总体来说我对数据绑定相对较新 首先 我有一个 ListView 控件 其中包含图像绑定
  • MySql 最后插入 ID,连接器 .net

    我正在使用 MySql Connector net 我需要获取最后一个查询生成的插入 id 现在 我假设返回值是MySqlHelper ExecuteNonQuery应该是最后一个插入id 但它只返回1 我正在使用的代码是 int inse
  • 使用 JSON 格式正确配置 NLog 到 IHostBuilder

    我有以下代码 应该接受 NLog 的 JSON appsettings 配置 然后使用它来创建 NLog LogFactory 这个 NLog 工厂应该被传递到 MyService 类中 以便在那里创建一个记录器 class Program
  • 使用预编译头减少 clang 编译时间

    我正在开发一个数据库项目 该项目将查询 以某种高级语言表示 编译为 C 代码 这段代码由数据库编译并执行 那部分工作得很好 现在 我正在尝试减少 C 查询代码的编译时间 我想知道是否可以使用预编译头来提高性能 该查询被转换为一个名为 Que
  • 将 Python 控制台集成到 GUI C++ 应用程序中

    I m going to add a python console widget into a C GUI below some other controls 许多类将暴露给 python 代码 包括一些对 GUI 的访问 也许我会考虑 P
  • 在不使用 ncurses 的情况下用 C/C++ 编写“真正的”交互式终端程序,例如 vim、htop...

    不 我不想使用ncurses 因为我想了解如何 终端可以工作 并且我自己编程也很有趣 没有 必须是可移植的 它必须只能在基于 linux xterm 的终端仿真器上工作 我想做的是编写一个交互式终端应用程序 例如 htop 和 vim 我的
  • 求一个数的因数。无法得到准确的结果

    有人可以帮助纠正我的算法吗 我已经对几个数字进行了测试 但它没有输出完整的因式分解 对于具有大量因子的数字 它完全失败 int num 20 for int i 2 i lt num i if num i 0 cout lt lt i lt
  • C for 循环索引:新 CPU 中的前向索引更快吗?

    在我订阅的邮件列表上 两位知识渊博的 IMO 程序员正在讨论一些优化的代码 并说了以下内容 在 5 8 年前发布的 CPU 上 向后迭代 for 循环稍微快一些 e g for int i x 1 i gt 0 i 因为比较i归零比将其与其
  • 捕获另一个进程未处理的异常

    我想知道我是否可以捕获我开始使用 Process Start 的另一个进程抛出的未处理的异常 我知道我可以用这个捕获标准错误link http social msdn microsoft com Forums en US csharpgen
  • 如何填充两个样条线或直线系列之间的区域

    我有这个Chart 如何填充两个之间的区域Series S0 and S1 说蓝色和黄色Series 为此 我们编写了其中之一Paint事件 这里的ValueToPixelPosition https msdn microsoft com
  • ASP.NET MVC 路由 - 向路由添加 .html 扩展名

    我对 MVC 和路由非常陌生 我被要求修改一个应用程序以使用不同的 url 由于我没有经验 这项任务对我来说有点困难 好吧 让我们谈谈一些代码 routes MapRoute CategoryBySeName Route name prod
  • 使用宏计算源文件行数?

    是否可以使用 C C 预处理器将源文件中的行数计算为宏或某种编译时可用值 例如 我可以更换吗MAGIC1 MAGIC2 and MAGIC3在下面 并在使用时以某种方式获取值 4MAGIC3 MAGIC1 can be placed whe
  • printf() 使用字符串表“解码器环”调试库

    我写这封信是想看看你们中是否有人见过或听说过我即将描述的想法的实现 我有兴趣为嵌入式目标开发 printf 风格的调试库 目标非常遥远 并且我和目标之间的通信带宽预算非常紧张 因此我希望能够以非常有效的格式获取调试消息 通常 调试语句如下所
  • 带有自定义鉴别器的 EntityFramework Code First 继承

    我正在尝试在 EntityFramework Code First 中映射以下继承 public class Member public string ProjectName get set public string AssemblyNa
  • SQL参数化查询不显示结果

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

    这个问题在这里已经有答案了 我知道它用于使用命令行中的参数 但我没有得到声明 字符 argv 它是否意味着指向 char 数组的指针 如果是的话为什么没有大小 如果不是动态数组 就不需要有大小吗 我做了一些研究 发现有人说它会衰减为 cha
  • 未找到 _sqlite3_open 等符号错误

    您好 我收到此错误 Undefined symbols sqlite3 open referenced from main in ccRlWVer o sqliite3 close referenced from main in ccRlW
  • 在 C# WinForms 中预览文档(Word、Excel、PDF、文本文件等)?

    我正在开发一个 C WinForms 应用程序 我希望能够 预览 其中的各种文档类型 也就是说 当用户从列表中选择文件名时 它会在下面以相同的形式显示所选文件的预览 这很像 Outlook 允许您无需双击即可预览选定邮件的方式 有没有什么方
  • 清理堆分配对象的良好实践或约定?

    我正在学习C 我有 C C ObjC 背景 相当高级的语言 在 C 或 ObjC 上 作为函数或方法的结果返回堆分配的对象是很简单的 因为对象的清理是受管理的 按照惯例 会在适当的时候销毁 但我不知道在 C 中应该如何处理这个问题 例如 s

随机推荐

  • 直接从 numpy 进行 h.264 编码

    我想直接从视频帧的 numpy 数组中编码视频 Open cv 通过以下方式提供此类功能cv2 VideoWriter 但是我需要 h 264 编解码器 但该编解码器不可用 到目前为止 我最好的方法是使用 open cv 编写视频 然后通过
  • Telegram 机器人 - OAuth 授权

    我想在我的机器人上通过 Twitch API 实现 OAuth 授权 当我寻找更好的解决方案时 我发现了这个 GitHubBot 在此机器人重定向 URL 中 从integrations telegram org github 开始 我想知
  • Struts2 JSON 插件:添加 ActionMessages、ActionErrors 和 FieldErrors 到响应

    我正在制作 JQuery Ajax 帖子 并且想要任何actionmessages actionerrors and fielderrors添加到响应中的操作中 以 JSON 格式 我添加了这个结果
  • Android设置位图到Imageview

    您好 我有一个 Base64 格式的字符串 我想将它转换为位图 然后将其显示到 ImageView 这是代码 ImageView user image Person person object Override protected void
  • @RequestBody如何区分未发送的值和空值?

    PatchMapping update HttpEntity
  • PouchDB:过滤、排序和分页

    与这两个 CouchDB 问题非常相似 3311225 https stackoverflow com questions 3311225 couchdb sorting and filtering in the same view and
  • 如何从 Flutter 中的字符串中删除/检测整个表情符号?

    我想在 Flutter 或 Dart 中模拟字符串中的键盘退格删除事件 就像是 String str hello 你们 myBackspace str will return hello 你们 myBackspace str will re
  • 具有与区域设置无关的 ID 的 get-counter

    我正在尝试通过 cmdlet 访问以下反向路径get counter以与语言环境无关的方式 Memory Pool Nonpaged Bytes 我按照中的说明进行操作这个线程 https stackoverflow com questio
  • 网络应用程序应该具有自动更新功能吗?

    在看到 Microsoft 给人们升级 Internet Explorer 6 时遇到的一些问题以及 Firefox 如何进行自动更新后 我开始考虑我们的 Web 应用程序的推送式升级系统的优点和缺点 您认为网络应用程序应该具有自动更新功能
  • NodeJS 4 和 5 npm 安装 bcrypt 和 db-migrate 失败

    前一段时间我安装了 NodeJS v0 10 31 并在一个项目上工作没有问题 但最近我决定更新到 Node v5 0 0 一切都很好 直到我决定使用 bcrypt 和 db migrate 调用命令npm 安装将无法吐出一长串详细信息 但
  • Magento - 通过库存查找缺货产品

    在我的 Magento 商店中 在将新库存添加到缺货商品后 我有时会忘记从下拉列表中选择 有货 是否有可能以某种方式获取所有有库存但标记为 缺货 的产品的列表 如果您能够快速编写一些脚本 products Mage getModel cat
  • Django 管理员:如何过滤整数字段以获取特定范围的值

    如何在 Django Admin 中创建过滤器以仅显示整数值位于两个值之间的记录 例如 如果我有一个模型 Person 它具有年龄属性 并且我只想显示年龄在 45 到 65 之间的 Person 记录 您可以使用以下方式过滤字段querys
  • numpy:累积多重数计数

    我有一个可能有重复的有序整数数组 我想计算连续的相等值 当一个值与前一个值不同时从零重新开始 这是使用简单的 python 循环实现的预期结果 import numpy as np def count multiplicities a r
  • 用于测试私有方法的Java工具?

    对于测试私有方法的意义有不同的看法 例如 here https softwareengineering stackexchange com questions 16732 unit testing internal components a
  • 使用本机 CSS 和 HTML 设置漏斗堆栈布局样式

    我想显示类似漏斗堆栈的数据 如下图所示 我能够使用边框创建锥度 例如 div class taper div 并使用以下 CSS taper width 200px height 0px border color lightgray tra
  • 如何在应用程序启动时获取旋转进度条

    我是安卓新手 我设法将 JSON 文件解析到我的应用程序中 现在我想使用 AsyncTask 获取 Spinning ProgressBa 直到应用程序启动并加载数据 我尝试阅读很多内容 但它们只给出如何获取 onclick 事件或下载事件
  • 广播接收器 onReceive 在位置更改时触发两次

    我想知道用户何时关闭 GPS 我想了解不同活动中的这一行动 我制作了广播接收器来监听 GPS 状态的变化 但几乎总是当我关闭 GPS 时 我的 updateValue 函数会被触发两次 当用户关闭 GPS 时如何收到通知 我做错了什么 下面
  • 使用 GData 进行搜索查询的 YouTube UITableView

    我正在尝试自定义表格视图以根据搜索查询显示 YouTube 视频的提要 我找到了这段代码http pastebin com vmV2c0HT http pastebin com vmV2c0HT它在表格视图中显示 YouTube 频道的提要
  • DisabledBackend:Celery、Redis 和 Flask 的不稳定行为

    我已经使用 Celery 一段时间了 在生产中我使用 RabbitMQ 作为代理 使用 Redis 作为 K8s 集群中的后端 到目前为止没有任何问题 在本地 我运行一个包含一些服务 Flask API 2 个不同的 Workers Bea
  • emgucv:C# 中的 pan 卡不正确的倾斜检测

    我有三个泛卡图像 用于使用 emgucv 和 c 测试图像的倾斜 顶部的第一张图像检测到 180 度工作正常 中间的第二张图像检测到的 90 度应检测为 180 度 第三张图像检测到 180 度应检测为 90 度 我想在这里分享的一个观察结