如何去除凸度缺陷?

2024-02-23

我正在尝试从轮廓检测并精细定位图像中的某些对象。我得到的轮廓通常包含一些噪音(可能来自背景,我不知道)。这些对象应该看起来类似于矩形或正方形,如下所示:

我通过形状匹配得到了非常好的结果(cv::matchShapes)来检测其中包含或不包含噪声的对象的轮廓,但是在有噪声的情况下,我在精细定位方面遇到了问题。

噪音看起来像:

enter image description here or enter image description here for example.

我的想法是找到凸性缺陷,如果它们变得太强,则以某种方式切除导致凹性的部分。检测缺陷是可以的,通常每个“不需要的结构”我都会得到两个缺陷,但我坚持如何决定应该从轮廓中删除哪些点以及在哪里删除点。

以下是一些轮廓、它们的掩模(以便您可以轻松提取轮廓)和包含阈值凸度缺陷的凸包:

我可以遍历轮廓并局部决定轮廓是否执行“左转”(如果顺时针行走),如果是,则删除轮廓点,直到进行下一个左转?也许从凸性缺陷开始?

我要的是算法还是代码,编程语言应该不重要,算法更重要。


这种方法仅适用于点。您不需要为此创建蒙版。

主要思想是:

  1. 查找轮廓上的缺陷
  2. 如果我发现至少两个缺陷,请找到两个最接近的缺陷
  3. 从轮廓中删除两个最接近的缺陷之间的点
  4. 在新轮廓上从 1 重新开始

我得到以下结果。正如您所看到的,它有一些缺点smooth缺陷(例如第七张图像),但对于清晰可见的缺陷效果非常好。我不知道这是否能解决您的问题,但可以作为一个起点。实际上应该相当快(你当然可以优化下面的代码,特别是removeFromContour功能)。此外,该方法的唯一参数是凸性缺陷的量,因此它对于小缺陷斑点和大缺陷斑点都适用。

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int ed2(const Point& lhs, const Point& rhs)
{
    return (lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y);
}

vector<Point> removeFromContour(const vector<Point>& contour, const vector<int>& defectsIdx)
{
    int minDist = INT_MAX;
    int startIdx;
    int endIdx;

    // Find nearest defects
    for (int i = 0; i < defectsIdx.size(); ++i)
    {
        for (int j = i + 1; j < defectsIdx.size(); ++j)
        {
            float dist = ed2(contour[defectsIdx[i]], contour[defectsIdx[j]]);
            if (minDist > dist)
            {
                minDist = dist;
                startIdx = defectsIdx[i];
                endIdx = defectsIdx[j];
            }
        }
    }

    // Check if intervals are swapped
    if (startIdx <= endIdx)
    {
        int len1 = endIdx - startIdx;
        int len2 = contour.size() - endIdx + startIdx;
        if (len2 < len1)
        {
            swap(startIdx, endIdx);
        }
    }
    else
    {
        int len1 = startIdx - endIdx;
        int len2 = contour.size() - startIdx + endIdx;
        if (len1 < len2)
        {
            swap(startIdx, endIdx);
        }
    }

    // Remove unwanted points
    vector<Point> out;
    if (startIdx <= endIdx)
    {
        out.insert(out.end(), contour.begin(), contour.begin() + startIdx);
        out.insert(out.end(), contour.begin() + endIdx, contour.end());
    } 
    else
    {
        out.insert(out.end(), contour.begin() + endIdx, contour.begin() + startIdx);
    }

    return out;
}

int main()
{
    Mat1b img = imread("path_to_mask", IMREAD_GRAYSCALE);

    Mat3b out;
    cvtColor(img, out, COLOR_GRAY2BGR);

    vector<vector<Point>> contours;
    findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    vector<Point> pts = contours[0];

    vector<int> hullIdx;
    convexHull(pts, hullIdx, false);

    vector<Vec4i> defects;
    convexityDefects(pts, hullIdx, defects);

    while (true)
    {
        // For debug
        Mat3b dbg;
        cvtColor(img, dbg, COLOR_GRAY2BGR);

        vector<vector<Point>> tmp = {pts};
        drawContours(dbg, tmp, 0, Scalar(255, 127, 0));

        vector<int> defectsIdx;
        for (const Vec4i& v : defects)
        {
            float depth = float(v[3]) / 256.f;
            if (depth > 2) //  filter defects by depth
            {
                // Defect found
                defectsIdx.push_back(v[2]);

                int startidx = v[0]; Point ptStart(pts[startidx]);
                int endidx = v[1]; Point ptEnd(pts[endidx]);
                int faridx = v[2]; Point ptFar(pts[faridx]);

                line(dbg, ptStart, ptEnd, Scalar(255, 0, 0), 1);
                line(dbg, ptStart, ptFar, Scalar(0, 255, 0), 1);
                line(dbg, ptEnd, ptFar, Scalar(0, 0, 255), 1);
                circle(dbg, ptFar, 4, Scalar(127, 127, 255), 2);
            }
        }

        if (defectsIdx.size() < 2)
        {
            break;
        }

        // If I have more than two defects, remove the points between the two nearest defects
        pts = removeFromContour(pts, defectsIdx);
        convexHull(pts, hullIdx, false);
        convexityDefects(pts, hullIdx, defects);
    }


    // Draw result contour
    vector<vector<Point>> tmp = { pts };
    drawContours(out, tmp, 0, Scalar(0, 0, 255), 1);

    imshow("Result", out);
    waitKey();

    return 0;
}

UPDATE

处理近似轮廓(例如使用CHAIN_APPROX_SIMPLE in findContours)可能会更快,但轮廓的长度必须使用以下方法计算arcLength().

这是要替换的片段swapping部分removeFromContour:

// Check if intervals are swapped
if (startIdx <= endIdx)
{
    //int len11 = endIdx - startIdx;
    vector<Point> inside(contour.begin() + startIdx, contour.begin() + endIdx);
    int len1 = (inside.empty()) ? 0 : arcLength(inside, false);

    //int len22 = contour.size() - endIdx + startIdx;
    vector<Point> outside1(contour.begin(), contour.begin() + startIdx);
    vector<Point> outside2(contour.begin() + endIdx, contour.end());
    int len2 = (outside1.empty() ? 0 : arcLength(outside1, false)) + (outside2.empty() ? 0 : arcLength(outside2, false));

    if (len2 < len1)
    {
        swap(startIdx, endIdx);
    }
}
else
{
    //int len1 = startIdx - endIdx;
    vector<Point> inside(contour.begin() + endIdx, contour.begin() + startIdx);
    int len1 = (inside.empty()) ? 0 : arcLength(inside, false);


    //int len2 = contour.size() - startIdx + endIdx;
    vector<Point> outside1(contour.begin(), contour.begin() + endIdx);
    vector<Point> outside2(contour.begin() + startIdx, contour.end());
    int len2 = (outside1.empty() ? 0 : arcLength(outside1, false)) + (outside2.empty() ? 0 : arcLength(outside2, false));

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

如何去除凸度缺陷? 的相关文章

  • pytesseract 无法从图像中识别复杂的数学公式

    我在用pytesseractpython 中的模块 pytesseract从图像中识别文本 但它不适用于包含复杂数学公式 例如根 推导 积分数学问题或方程 的图像 代码2 py Import modules from PIL import
  • 两个图像之间的视频变形,FFMPEG/Minterpolate

    我正在尝试在 Ubuntu Linux 上的 bash 脚本中使用两个帧 png 图像 和 ffmpeg 的 minterpolate 过滤器制作一个快速且简单的变形视频 目的是稍后使用变形作为不同视频编辑器中相似视频之间的过渡 它适用于
  • 查找具有不同强度/亮度的相似图像

    假设我有如下图像 我可以选择什么来比较两个图像之间的相似度 显然它们是相同的图像 只是亮度不同 我找不到任何可行的方法 目前我最好的选择是训练 cnn 或自动编码器并比较输出的特征向量 但这似乎有点矫枉过正 任何提示将不胜感激 相当强大的工
  • 如何使用 AdaBoost 进行特征选择?

    我想使用 AdaBoost 从大量 100k 中选择一组好的特征 AdaBoost 的工作原理是迭代功能集并根据功能的执行情况添加功能 它选择对现有特征集错误分类的样本表现良好的特征 我目前正在 Open CV 中使用CvBoost 我得到
  • 使用多边形图层下方的轮廓线切割多边形

    我想根据高程将多边形图层切割成两部分 上部和下部 多边形可能是凸的或凹的 并且切割的位置可能彼此不同 等高线的间隔为 5m 这意味着我可能需要生成一个具有更紧凑的等高线的等高线 例如 1m 的间隔 关于如何做到这一点的任何想法 在 ArcG
  • 如何加速 svm.predict?

    我正在编写一个滑动窗口来提取特征并将其输入到 CvSVM 的预测函数中 然而 我偶然发现 svm predict 函数相对较慢 基本上 窗口以固定的步幅长度在图像比例上滑动穿过图像 遍历图像加上提取每个图像特征的速度 窗口大约需要 1000
  • 使用卡尔曼滤波器跟踪位置和速度

    我正在使用卡尔曼滤波器 恒定速度模型 来跟踪物体的位置和速度 我测量对象的 x y 并跟踪 x y vx vy 这是有效的 但是如果在传感器读数 x y vx vy 上添加 20 mm 的高斯噪声 即使该点没有移动 只是噪声也会发生波动 对
  • Fast R-CNN 中 ROI 层的用途是什么?

    In this https leonardoaraujosantos gitbooks io artificial inteligence content object localization and detection html关于目标
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 图像处理方面的空间和时间表征有什么区别?

    我是学习图像处理的初学者 我对空间和时间表征的概念有点困惑 那么 对于空间表征来说 是不是像一张二维地图 包含了一些关于地图的统计信息呢 就时间特征而言 值是相对于时间的吗 这意味着什么以及我们为何关心 谢谢 当您在不同时间拍摄一系列图像时
  • 基本矩阵错误?

    我试图通过扫描从相机拍摄的两个图像 检测图像中的特征 匹配它们 创建基本矩阵 使用相机内在函数计算基本矩阵 然后分解它以找到旋转和翻译 这是matlab代码 I1 rgb2gray imread 1 png I2 rgb2gray imre
  • opencv中如何去除二值图像噪声?

    将图像转换为二值图像 黑白 后如果有任何噪音怎么办 我消除了那些不需要的噪音 您可以看到下图的黑色区域内有一些白噪声 我该如何去除噪声 使用opencv http img857 imageshack us img857 999 blackn
  • Python绕相机轴旋转图像

    假设我有一个图像 是在对某些原始图像应用单应性变换 H 后获得的 未显示原始图像 将单应性 H 应用于原始图像的结果是该图像 我想围绕合适的轴 可能是相机所在的位置 如果有的话 将此图像旋转 30 度以获得此图像 如果我不知道相机参数 如何
  • 使用 OpenCV 进行图像模糊检测

    我正在研究图像的模糊检测 我已经用过拉普拉斯方法的方差在 OpenCV 中 img cv2 imread imgPath gray cv2 cvtColor img cv2 COLOR BGR2GRAY value cv2 Laplacia
  • 为什么这个基本的 imagejpeg() resizer 返回黑色图像?

    EDIT 感谢您的所有回答 特别是 Mailerdaimon 他注意到我没有在imagecopyresampled功能 我不再得到黑色图像 但我仍然得到一些黑色部分 所以我认为我的比例公式应该更新 如果我上传横向图像 新图像的高度小于 17
  • 在哪里可以找到有关双三次插值和 Lanczos 重采样的好读物?

    我想用 C 实现上述两种图像重采样算法 双三次和 Lanczos 我知道现有的实现有几十种 但我仍然想制作自己的实现 我之所以这么做 部分原因是我想了解它们是如何工作的 部分原因是我想为它们提供一些主流实现中没有的功能 例如可配置的多 CP
  • 估计 libGD 操作所需的内存

    在尝试使用 libGD 在 PHP 中调整图像大小之前 我想检查是否有足够的内存可用于执行该操作 因为 内存不足 会完全终止 PHP 进程并且无法捕获 我的想法是 原始图像和新图像中的每个像素 RGBA 需要 4 字节内存 check av
  • 如何使用PHP在服务器端缩小图像?

    我有一些从服务器提取的图像 imgUrl保存图像的路径 现在我用 img src width 100 height 200 或 CSS 来缩小图像 但我想在 PHP 中执行此操作 以便将已缩放的图像提供给 DOM 有任何想法吗 Thanks
  • 在 opencv 中一次性将旋转和平移结合起来

    我有一段用于旋转和平移图像的代码 Point2f pt 0 in rows double angle atan trans c trans b 180 M PI Mat r getRotationMatrix2D pt angle 1 0
  • 车辆分割和跟踪

    我已经从事一个项目一段时间了 目的是在无人机捕获的视频中检测和跟踪 移动 车辆 目前我正在使用 SVM 该 SVM 接受了从车辆和背景图像中提取的局部特征的特征袋表示的训练 然后 我使用滑动窗口检测方法来尝试定位图像中的车辆 然后我想要跟踪

随机推荐

  • 带有超链接的 Pandas read_excel

    我有一个 Excel 电子表格 正在将其读入 Pandas DataFrame df pd read excel file xls 但是 电子表格的其中一列包含具有与其关联的超链接的文本 如何访问 Pandas 中的底层超链接 这可以用 o
  • 自定义 UITableViewCell 内的水平 UIScrollView - 使用 IB Storyboard - 不滚动

    主要目标是能够水平滚动每行的内容 我正在尝试使用 X Code 5 和 StoryBoard 来做到这一点 问题似乎很简单 但是经过几个小时的搜索 除了一个有点相似但仅使用编程方法的问题之外 我什么也没得到 see here https s
  • Android 动画时删除视图错误

    private void kartyafeleanim String idx1 String idx2 Animation anim1 AnimationUtils loadAnimation mycontext R anim scalab
  • Oracle数据库:如何选择所有列但首先返回某些列?

    背景 我有一个 Oracle 数据库表 其中有很多列 我正在对这些列运行一些查询 我不知道我在查询中到底要查找什么数据 所以我想返回所有列 但我不想寻找和啄食我知道有意义的列 Question 假设有一个表 表 1 A 列 B 列 C 列
  • 将菜单按钮添加到 VS2010 TFS 查询结果或工作项栏中

    我正在尝试将按钮添加到 Visual Studio TFS2010 工作项查询结果菜单栏以及为各个工作项显示的菜单栏 见下图 这实际上是可定制的且可行的吗 如果可以 如何实现 我会看一下这篇文章 TFS 2010 将菜单项添加到构建资源管理
  • 从浏览器检测Windows 10

    我需要在客户端运行 Windows 10 S 特别是 S 仅 Win 10 还不够 时将浏览器重定向到特定页面 用户代理似乎没有指定这一点 我已经找到了在客户端上通过 C 和 WMI 获取此数据的解决方案 但我需要在网页上运行 Javasc
  • MvvmLight EventToCommand 和 WPFToolkit DataGrid 双击

    试图弄清楚如何使用 EventToCommand 为行设置数据网格双击处理程序 该命令位于每行的视图模型中 只是that很大程度上来自我的经验 因为我还没有使用过交互 Thanks 我本来会使用 mvvmlight 标签 但我还没有足够高的
  • 如何使用 Kotlin DSL 创建 Fat JAR?

    我正在使用 Gradle 5 5 我有一个基于 Groovy 的构建脚本 我正在尝试将其迁移到 Kotlin DSL 这jar任务包含将所有依赖项复制到 JAR 文件的典型行 from configurations compile coll
  • 打开键盘时隐藏页脚 ionic4

    参考了这个链接 在键盘打开 Ionic3 上隐藏页脚 https stackoverflow com questions 48386422 hide footer on keyboard open ionic3 但问题也是一样的 问题与上图
  • 如何使用 OSGi 和 EE6 模块化企业应用程序?

    我知道已经有一些与该主题相关的问题 但我还找不到真正的解决方案 目前我正在使用 EE6 JPA CDI JSF 开发应用程序 我想采用一种更加模块化的方法 而不是将所有内容打包到 WAR 或 EAR 中并将整个内容部署在应用程序服务器上 我
  • WooCommerce 在产品标题中显示产品类别

    我有一个运行 WooCommerce 版本 2 3 8 的 Wordpress 版本 4 2 2 电子商务网站 在我的个人产品页面上 我希望将产品的标题设置为还包括我在 WooCommerce 中创建的以及该产品所属的自定义类别 我找到与单
  • 项目贡献者的 github graphql 查询

    我想使用 GitHub Graphql api 查询项目贡献者 有人能给我任何提示吗 刚刚尝试了一段时间 我想我错过了一些小元素 我想要得到某样东西https api github com repos facebook react cont
  • 核心数据图像不会加载到 NSTableView 图像单元中

    在我的代码中 我将图像存储到我的核心数据模型中 工作正常 如果我将视图设置为具有 NSImageView 并将其数据绑定到 Controller Key selection 和 modelKeyPath myImagePath 则它可以工作
  • 如何通过htaccess在URL中添加index.php

    实际上我需要通过 htaccess 文件在我的应用程序 URL 中添加 index php 我的网址是这样的 http localhost 8080 myapp xyz abs html 我需要将其更改为 http localhost 80
  • 在 PHP 中检索相对 DOM 节点

    我想检索文档中下一个元素标签的数据 例如 我想找回 blockquote Content 1 blockquote 仅适用于每个不同的跨度 span span blockquote Content 1 blockquote blockquo
  • 如何生成一次性密码(OTP / HOTP)?

    我们决定通过为客户发布 iPhone Android 和 Blackberry 应用程序的方式开始进行多重身份验证 Think 的一次性密码系统 我知道如何生成一个独特的string通过使用基于帐户密钥加上设备序列号 或其他唯一标识符 的
  • FirstOrDefault 之后对象是否仍连接到列表?

    这是我的代码 Event thisEvent from i in list where i eventID eventID select i FirstOrDefault if thisEvent null thisEvent eventR
  • 命名空间“System.Data”中不存在类型或命名空间名称“OracleClient”

    当尝试运行我的代码时 我收到以下错误 CS0234 命名空间 System Data 中不存在类型或命名空间名称 OracleClient 是否缺少程序集引用 我已经引用了System Data dll and System Data Or
  • 无需安装即可替代 xuggler 进行视频编码? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在创建一个截屏 Java Web Start 应用程序 使用 xuggler 编码视频需要 在客户端
  • 如何去除凸度缺陷?

    我正在尝试从轮廓检测并精细定位图像中的某些对象 我得到的轮廓通常包含一些噪音 可能来自背景 我不知道 这些对象应该看起来类似于矩形或正方形 如下所示 我通过形状匹配得到了非常好的结果 cv matchShapes 来检测其中包含或不包含噪声