信中信,模式识别

2023-12-12

我想检测这种模式

https://www.dropbox.com/s/ghuaywtfdsb249j/test.jpg

正如您所看到的,它基本上是一个字母 C,位于另一个字母内部,具有不同的方向。我的模式可以相互包含多个 C,我发布的带有 2 个 C 的模式只是一个示例。我想检测有多少个 C,以及每个 C 的方向。现在我已经成功地检测到了这种模式的中心,基本上我已经成功地检测到了最里面的 C 的中心。您能给我提供关于我可以使用的不同算法的任何想法吗?


现在我们开始! A 高层次概述这种方法的过程可以描述为以下步骤的顺序执行:

  • 加载输入图像;
  • 将其转换为灰度;
  • 临界点它生成二值图像;
  • 使用二值图像找到轮廓;
  • 填充轮廓的每个区域使用不同的颜色(这样我们可以单独提取每个字母);
  • 为找到的每个字母创建一个遮罩,将它们隔离在单独的图像中;
  • 将图像裁剪为尽可能小的尺寸;
  • 找出图像的中心;
  • 计算出字母边框的宽度,以确定边框的确切中心;
  • 沿着边界(以圆形方式)扫描是否有不连续性;
  • 找出不连续点的大致角度,从而确定字母的旋转量。

由于我正在共享源代码,因此我不想讨论太多细节,因此请随意测试并以您喜欢的任何方式更改它。 开始吧,冬天来了:

#include <iostream>
#include <vector>
#include <cmath>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

cv::RNG rng(12345);
float PI = std::atan(1) * 4;

void isolate_object(const cv::Mat& input, cv::Mat& output)
{    
    if (input.channels() != 1)
    {
        std::cout << "isolate_object: !!! input must be grayscale" << std::endl;
        return;
    }

    // Store the set of points in the image before assembling the bounding box
    std::vector<cv::Point> points;
    cv::Mat_<uchar>::const_iterator it = input.begin<uchar>();
    cv::Mat_<uchar>::const_iterator end = input.end<uchar>();
    for (; it != end; ++it)
    {
        if (*it) points.push_back(it.pos());
    }

    // Compute minimal bounding box
    cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));

    // Set Region of Interest to the area defined by the box
    cv::Rect roi;
    roi.x = box.center.x - (box.size.width / 2);
    roi.y = box.center.y - (box.size.height / 2);
    roi.width = box.size.width;
    roi.height = box.size.height;

    // Crop the original image to the defined ROI
    output = input(roi);
}

有关实施的更多详细信息isolate_object() please 检查这个线程. cv::RNG稍后用于用不同的颜色填充每个轮廓, and PI,嗯...你知道PI.

int main(int argc, char* argv[])
{   
    // Load input (colored, 3-channel, BGR)
    cv::Mat input = cv::imread("test.jpg");
    if (input.empty())
    {
        std::cout << "!!! Failed imread() #1" << std::endl;
        return -1;
    }

    // Convert colored image to grayscale
    cv::Mat gray;
    cv::cvtColor(input, gray, CV_BGR2GRAY);

    // Execute a threshold operation to get a binary image from the grayscale
    cv::Mat binary;
    cv::threshold(gray, binary, 128, 255, cv::THRESH_BINARY); 

The binary图像看起来与输入完全相同,因为它只有 2 种颜色(黑白):

    // Find the contours of the C's in the thresholded image
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(binary, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);

    // Fill the contours found with unique colors to isolate them later
    cv::Mat colored_contours = input.clone();  
    std::vector<cv::Scalar> fill_colors;   
    for (size_t i = 0; i < contours.size(); i++)
    {
        std::vector<cv::Point> cnt = contours[i];
        double area = cv::contourArea(cv::Mat(cnt));        
        //std::cout << "* Area: " << area << std::endl;

        // Fill each C found with a different color. 
        // If the area is larger than 100k it's probably the white background, so we ignore it.
        if (area > 10000 && area < 100000)
        {
            cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));            
            cv::drawContours(colored_contours, contours, i, color, 
                             CV_FILLED, 8, std::vector<cv::Vec4i>(), 0, cv::Point());
            fill_colors.push_back(color);
            //cv::imwrite("test_contours.jpg", colored_contours);
        }           
    }

What 彩色轮廓好像:

    // Create a mask for each C found to isolate them from each other
    for (int i = 0; i < fill_colors.size(); i++)
    {
        // After inRange() single_color_mask stores a single C letter
        cv::Mat single_color_mask = cv::Mat::zeros(input.size(), CV_8UC1);
        cv::inRange(colored_contours, fill_colors[i], fill_colors[i], single_color_mask);
        //cv::imwrite("test_mask.jpg", single_color_mask);

从此for循环执行两次,每次用于填充轮廓的颜色一次,我希望您看到此阶段生成的所有图像。所以下面的图像是由单一颜色掩码(循环的每次迭代一个):

        // Crop image to the area of the object
        cv::Mat cropped;
        isolate_object(single_color_mask, cropped);        
        //cv::imwrite("test_cropped.jpg", cropped);
        cv::Mat orig_cropped = cropped.clone();

这些是存储的cropped(顺便说一句,较小的 C 看起来很胖,因为图像已被此页面重新缩放以具有与较大的 C 相同的大小,不用担心):

        // Figure out the center of the image
        cv::Point obj_center(cropped.cols/2, cropped.rows/2);
        //cv::circle(cropped, obj_center, 3, cv::Scalar(128, 128, 128));
        //cv::imwrite("test_cropped_center.jpg", cropped);

为了更清楚地理解什么对象中心是为了,出于教育目的,我在该位置画了一个小灰色圆圈:

        // Figure out the exact center location of the border
        std::vector<cv::Point> border_points;
        for (int y = 0; y < cropped.cols; y++) 
        {
            if (cropped.at<uchar>(obj_center.x, y) != 0)
                border_points.push_back(cv::Point(obj_center.x, y));

            if (border_points.size() > 0 && cropped.at<uchar>(obj_center.x, y) == 0)
                break;
        }

        if (border_points.size() == 0)
        {
            std::cout << "!!! Oops! No border detected." << std::endl;
            return 0;
        }

        // Figure out the exact center location of the border
        cv::Point border_center = border_points[border_points.size() / 2];
        //cv::circle(cropped, border_center, 3, cv::Scalar(128, 128, 128));
        //cv::imwrite("test_border_center.jpg", cropped);

上述程序扫描单个垂直线从图像的顶部/中间找到圆的边界,以便能够计算其宽度。再次,出于教育目的,我在边框中间画了一个灰色的小圆圈。这是什么cropped好像:

        // Scan the border of the circle for discontinuities 
        int radius = obj_center.y - border_center.y;
        if (radius < 0) 
            radius *= -1;  
        std::vector<cv::Point> discontinuity_points;   
        std::vector<int> discontinuity_angles;
        for (int angle = 0; angle <= 360; angle++)
        {
            int x = obj_center.x + (radius * cos((angle+90) * (PI / 180.f))); 
            int y = obj_center.y + (radius * sin((angle+90) * (PI / 180.f)));                

            if (cropped.at<uchar>(x, y) < 128)
            {
                discontinuity_points.push_back(cv::Point(y, x));
                discontinuity_angles.push_back(angle); 
                //cv::circle(cropped, cv::Point(y, x), 1, cv::Scalar(128, 128, 128));                           
            }
        }

        //std::cout << "Discontinuity size: " << discontinuity_points.size() << std::endl;
        if (discontinuity_points.size() == 0 && discontinuity_angles.size() == 0)
        {
            std::cout << "!!! Oops! No discontinuity detected. It's a perfect circle, dang!" << std::endl;
            return 0;
        }

太好了,上面的代码片段沿着圆边界的中间扫描,寻找不连续性。我正在分享一个示例图像来说明我的意思。图像上的每个灰点代表一个被测试的像素。当像素为黑色时,意味着我们发现了不连续性:

enter image description here

        // Figure out the approximate angle of the discontinuity: 
        // the first angle found will suffice for this demo.
        int approx_angle = discontinuity_angles[0];        
        std::cout << "#" << i << " letter C is rotated approximately at: " << approx_angle << " degrees" << std::endl;    

        // Figure out the central point of the discontinuity
        cv::Point discontinuity_center;
        for (int a = 0; a < discontinuity_points.size(); a++)
            discontinuity_center += discontinuity_points[a];
        discontinuity_center.x /= discontinuity_points.size(); 
        discontinuity_center.y /= discontinuity_points.size(); 
        cv::circle(orig_cropped, discontinuity_center, 2, cv::Scalar(128, 128, 128));

        cv::imshow("Original crop", orig_cropped);
        cv::waitKey(0);
    }

    return 0;
}

很好...最后一段代码负责计算不连续性的大致角度并指示不连续性的中心点。以下图像存储于原始裁剪。我再次添加了一个灰点来显示检测到的间隙中心的确切位置:

执行时,该应用程序将以下信息打印到屏幕上:

#0 letter C is rotated approximately at: 49 degrees
#1 letter C is rotated approximately at: 0 degrees 

我希望它有帮助。

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

信中信,模式识别 的相关文章

  • OpenCV Android - 无法解析相应的JNI函数

    我正在尝试按照此处概述的本教程使用 Opencv 设置 Android Studio https www youtube com watch v OTw GIQNbD8 https www youtube com watch v OTw G
  • 如何在 C# 中将位图图像转换为黑白图像? [复制]

    这个问题在这里已经有答案了 可能的重复 在 c 中将图像转换为黑白或棕褐色 https stackoverflow com questions 4624998 convert image to black white or sepia in
  • MATLAB 教程中的 SIFT 实现

    我正在寻找 MATLAB 中的一些基本 SIFT 实现 我需要从第一原则来写它 另外 我正在寻找一些可以解释程序中发生的事情的内容 Vedali 的代码和 David Lowe 的代码超出了我的理解范围 如果您是 Matlab 用户 您一定
  • OpenCV:如何使用图像计算相机和物体之间的距离?

    我是 OpenCV 的新手 我正在使用以下公式来计算距离 distance to object mm focal length mm real height of the object mm image height pixels obje
  • Pytorch RuntimeError:张量 a (4) 的大小必须与非单维 0 处张量 b (3) 的大小匹配

    我使用的代码来自here https www learnopencv com image classification using transfer learning in pytorch 训练模型来预测印刷样式编号0 to 9 idx t
  • 使用 SURF 在检测到的对象周围绘制矩形

    我正在尝试从涉及冲浪检测器的以下代码中检测对象 我不想绘制匹配项 我想在检测到的对象周围绘制一个矩形 但不知何故我无法获得正确的单应性 请任何人指出在哪里我走错了 include
  • OpenCV Python RTSP 流

    我想使用 RTSP 从 IP 摄像机流式传输视频 但我有一个问题 我已经安装了先决条件 而且我的 RTSP 链接可以在 VlC 播放器上运行 但是当我在编辑器中尝试并运行它时 它说找不到相机 这是我的代码 import cv2 import
  • VideoCapture 未检测到 uEye 摄像头

    我的 uEye 相机遇到了一个问题 使用我的笔记本电脑摄像头 id 0 或 USB 上的网络摄像头 id 1 此行完美运行 TheVideoCapturer open 1 TheVideoCapturer 属于 VideoCapture 类
  • PyTorch 中的数据增强

    我对 PyTorch 中执行的数据增强有点困惑 现在 据我所知 当我们执行数据增强时 我们保留原始数据集 然后添加它的其他版本 翻转 裁剪 等 但 PyTorch 中似乎并没有发生这种情况 据我从参考文献中了解到 当我们使用data tra
  • OpenCV 读取视频文件时内存不足

    此示例从文件中读取视频cv2 VideoCapture在 python OpenCV 中内存不足 import cv2 cap cv2 VideoCapture file mp4 while True ret frame cap read
  • Android for OpenCV - 打开跟踪文件时出错,UnsatisfiedLinkError

    我对 Android 开发和 OpenCV 都是新手 我从 Android 下载了 OpenCV 库http sourceforge net projects opencvlibrary files opencv android http
  • 减少非常大图像的文件大小,而不改变图像尺寸

    考虑一个处理可能非常大的 PNG 文件上传的应用程序 所有上传的文件必须存储到磁盘以供以后检索 但是 PNG 文件的大小最大可达 30 MB 但磁盘存储限制规定每个文件的最大大小为 1 MB 问题是获取文件大小高达 30 MB 的输入 PN
  • 如何将 OpenCV 的测试框架与 CMake 结合使用?

    好像 OpenCV 有一个测试框架 https github com Itseez opencv tree ef91d7e8830c36785f0b6fdbf2045da48413dd76 modules ts include opencv
  • 将yuv420p原始数据转换为opencv图像

    我有来自 rtmp 服务器的原始数据 像素格式为 yuv420p 我使用管道来读取数据 但我不知道如何将原始数据解码为图像 command ffmpeg command extend loglevel fatal i rtmp localh
  • 在 Python 中使用音频流 RTMP 通过管道和 OpenCV 到 FFmpeg

    我正在尝试使用音频流式传输 FFmpeg 我将在下面展示我的代码 导入模块 import subprocess as sp 创建变量 rtmpUrl rtmp a rtmp youtube com live2 key camera path
  • 从凸点获取角点

    我编写了算法来提取图像中显示的点 它们形成凸形 我知道它们的顺序 如何从这些点中提取角点 顶部 3 个和底部 3 个 我正在使用opencv 如果你已经有了物体的凸包 并且该包包含角点 那么你需要做的就是简化包直到它只有 6 个点 有很多方
  • Java - 调整图像大小而不损失质量

    我有 10 000 张照片需要调整大小 因此我有一个 Java 程序来执行此操作 不幸的是 图像的质量损失很大 而且我无法访问未压缩的图像 import java awt Graphics import java awt AlphaComp
  • 调整图像的亮度、对比度和伽玛值

    在 NET 中调整图像的亮度 对比度和伽玛值的简单方法是什么 c and gdi have a simple way to control the colors that are drawn It s basically a ColorMa
  • MATLAB 中的霍夫变换

    有谁知道如何使用霍夫变换来检测二值图像中最强的线 A zeros 7 7 A 6 10 18 24 36 38 41 1 使用 rho theta 格式 其中 theta 以 45 为步长 从 45 到 90 以及如何在 MATLAB 中显
  • 计数物体和更好的填充孔的方法

    我是 OpenCV 新手 正在尝试计算物体的数量在图像中 我在使用 MATLAB 图像处理工具箱之前已经完成了此操作 并在 OpenCV Android 中也采用了相同的方法 第一步是将图像转换为灰度 然后对其进行阈值计算 然后计算斑点的数

随机推荐

  • 覆盖 XML 序列化方法

    我在尝试自定义 DateTime 变量在我的对象中序列化的方式时遇到问题 我希望它输出为 2011 09 26T13 00 00Z 但是当我重写 GetObjectData 函数 我认为这是执行此操作的方法 时 根本不会为它们输出任何 XM
  • 带有动态选项组的下拉列表

    嗨 cakephp 专家 我正在寻求您对带有动态 optgroup 的动态下拉列表的帮助 假设我有两个表 countries id country name counties id county name country id 现在 我想显
  • Android-NavigationView从右到左

    我正在使用 Android Studio 1 5 的最新版本 我想使用抽屉布局制作一个菜单 用于定位其调用 GravityCompat 我正在尝试使用这个组件并修改它 将抽屉从右向左放置 这是我的代码 public class MainAc
  • iOS 8 中的 NSDateFormatter 日期格式问题

    我有一个 NSDateFormatter 用来将 NSDate 格式化为字符串 以下格式不起作用 ddMMyyyy hhmmss SSS 当我尝试格式化 NSDate 时 我得到以下输出 18092014 08 49 03 638 其中有一
  • Azure 搜索是否处理同义词

    Azure 搜索 可以根据同义词进行搜索吗 例如 如果我搜索 鞋类 系统应该获取以下结果 鞋类的同义词 如鞋子 凉鞋等 我进行了很多搜索 但未能找到有关它的适当文档 我能找到的最接近的是一个帖子说它还不支持 但这是一个旧帖子 https s
  • 从静态方法调用 startActivityForResult

    我有一个按钮监听器 当用户单击按钮时我想启动相机意图 目前我有这个 public class ButtonListener implements View OnClickListener private ArrayList
  • 在整个页面加载之前显示加载栏

    我想在加载整个页面之前显示一个加载栏 目前 我只是使用了一个小的延迟 document ready function page fadeIn 2000 该页面已使用 jQuery 注意 我已经尝试过这个 但它对我不起作用 脚本运行时加载栏
  • Python“for i in”+变量

    我有以下代码 Euler Problem 1 print We are going to solve Project Euler s Problem 1 euler number input What number do you want
  • 如何在Linux上指定时间运行脚本? [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我有一个包含特定日期和时间的文本文件 我希望能够在该文件中指定的时间运行脚本 你将如何实现这一目标 创建另一个在后台运行的脚本 类似于守护程序 并每秒检查当前时间是否与文件中的时间匹
  • 将电子邮件另存为 MSG 文件,无需使用 Outlook(COM 对象等)或第 3 方软件

    现在 我正在使用 Exchange Web 服务 API 和 PowerShell 从 Exchange 中提取特定电子邮件并将其保存为 EML 文件 这很好用 但是 用户 客户要求电子邮件采用 msg 格式 我见过有两种方法可以做到这一点
  • 录制时拍摄相机屏幕截图 - 就像 Galaxy S3 一样?

    我正在开发一个使用 SurfaceView 进行显示的相机应用程序 我可以截取 SurfaceView 的屏幕截图 并将其保存为位图 使用 getDrawingCache 在包装 SurfaceView 的布局上 还有canvas draw
  • VBA:等待 Bloomberg BDP 通话完成

    我有一个脚本将一些外部数据导入到工作表中 这反过来会影响一些 BDP 公式 最好 我想在复制数据后立即对 BDP 结果进行一些检查 Bloomberg Excel 插件异步更新 如何等待结果然后恢复脚本 似乎只有在 VBA 脚本完成后才会导
  • 为 Nitrogen6x 构建 Qt 5 时出现 libm 重定位错误

    我正在尝试在 Qt 5 上构建氮气6x板由 i MX6Q 供电 我已经安装了Debian 喘息在板上 我正在使用乌班图12 10交叉编译机 配置 Qt 就像一个魅力 但我陷入了 make 步骤 这是我运行的配置脚本 configure v
  • 如何设计一封安全且“自毁”的电子邮件?

    正如大多数人所知 电子邮件非常不安全 即使客户端和发送电子邮件的服务器之间有 SSL 安全连接 消息本身在 Internet 上的节点间跳跃时也将采用明文形式 从而容易被窃听 另一个考虑因素是 发件人可能不希望邮件在一段时间后或在被阅读一次
  • 读取 PDF 文档中的所有书签,并使用书签的页码和标题创建字典

    我尝试使用 Python 和 PyPDF2 包来阅读 PDF 文档 目标是读取pdf中的所有书签 并构建一个以书签页码为键 书签标题为值的字典 互联网上没有太多关于如何实现它的支持 除了this文章 其中发布的代码不起作用 我不是 pyth
  • 无法将我自己的域添加到 google api 通知端点

    我正在尝试使用谷歌推送通知 我已经关注了此处列出的注册过程 简而言之 我的领域已在 https 中验证在 Google 网站管理员工具中 但是 当我尝试添加通知端点在 Google Cloud Console 中 我收到以下错误 You d
  • (git tfs fetch)TF400324:Team Foundation 服务不可用,底层连接已关闭

    我使用 git tfs 已经快 5 年了 然后有一天我在运行时遇到以下错误git tfs fetch TF400324 Team Foundation services are not available from server https
  • 如何在低于 KitKat 的 Android 版本的 Android WebView 中重置代理?

    我使用以下 2 种方法在 Android WebView 中为 Android 版本 ICS 和 JB 设置代理 但我无法重置 删除这两个版本的代理 如何重置 删除通过这些方法设置的代理 For ICS private static boo
  • 使用 Perl 获取 WMI 内存值

    我需要使用WMI收集Windows操作系统的内存数据 从这个意义上说 我开发了一个 Perl 脚本来生成此类数据 但是 我想知道我的方法是否正确以及有哪些替代方案 收集数据的方法旨在尽可能广泛地应用于 Windows 操作系统 如果你不是一
  • 信中信,模式识别

    我想检测这种模式 正如您所看到的 它基本上是一个字母 C 位于另一个字母内部 具有不同的方向 我的模式可以相互包含多个 C 我发布的带有 2 个 C 的模式只是一个示例 我想检测有多少个 C 以及每个 C 的方向 现在我已经成功地检测到了这