如何提高索贝尔边缘检测器的效率

2024-02-29

我正在写一个计算机视觉库 https://github.com/RoadKillCat/PiCamVision从头开始使用 Python 来使用rpi相机。目前,我已经实现了转换为greyscale以及其他一些基本的img在我的设备上运行速度相对较快的操作model B rpi3.

然而,我的边缘检测功能使用sobel操作员 (维基百科描述 https://en.wikipedia.org/wiki/Sobel_operator)尽管它确实有效,但比其他函数慢得多。这里是:

def sobel(img):
    xKernel = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
    yKernel = np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
    sobelled = np.zeros((img.shape[0]-2, img.shape[1]-2, 3), dtype="uint8")
    for y in range(1, img.shape[0]-1):
        for x in range(1, img.shape[1]-1):
            gx = np.sum(np.multiply(img[y-1:y+2, x-1:x+2], xKernel))
            gy = np.sum(np.multiply(img[y-1:y+2, x-1:x+2], yKernel))
            g = abs(gx) + abs(gy) #math.sqrt(gx ** 2 + gy ** 2) (Slower)
            g = g if g > 0 and g < 255 else (0 if g < 0 else 255)
            sobelled[y-1][x-2] = g
    return sobelled

并用这个运行它greyscale猫的图像:

我得到这样的回应,这似乎是正确的:

该库的应用,特别是该功能,是在下棋机器人上,其中边缘检测将有助于识别棋子的位置。问题是需要>15运行秒数是一个重大问题,因为它会大大增加机器人移动所需的时间。

我的问题是:我怎样才能加快速度?

到目前为止,我已经尝试了几件事:

  1. 代替squaring then adding, then square rooting the gx and gy值来获得总梯度,我只是sum the absolute价值观。这大大提高了速度。

  2. 使用较低的resolution图像来自rpi相机。这显然是一种使这些操作运行得更快的简单方法,但它并不是那么可行,因为在最低可用分辨率下它仍然相当慢480x360这比相机的最大3280x2464.

  3. 编写嵌套的 for 循环来执行以下操作matrix convolutions代替np.sum(np.multiply(...))。这最终有点slower我对此感到惊讶,因为从那时起np.multiply返回一个新数组,我认为这样做应该更快loops。我认为这可能是因为numpy大部分写在C或者新数组实际上并未存储,因此不需要很长时间,但我不太确定。

任何帮助将不胜感激 - 我认为改进的主要内容是点3,即matrix乘法和求和。


即使您正在构建自己的库,您确实绝对应该使用库进行卷积,它们将在后端用 C 或 Fortran 执行结果操作,这会快得多。

但如果您愿意的话,可以使用线性可分离滤波器自行完成。想法是这样的:

Image:

1 2 3 4 5
2 3 4 5 1
3 4 5 1 2

Sobel x kernel:

-1 0 1
-2 0 2
-1 0 1

Result:

8, 3, -7

在卷积的第一个位置,您将计算 9 个值。首先,为什么?你永远不会添加中间的列,也不必费心去乘它。但这不是线性可分离滤波器的重点。这个想法很简单。当您将内核放在第一个位置时,您将把第三列乘以[1, 2, 1]。但两步后,您将第三列乘以[-1, -2, -1]。多么浪费啊!你已经计算过了,你现在只需要将它否定即可。这就是线性可分离滤波器的想法。请注意,您可以将过滤器分解为两个向量的矩阵外积:

[1]
[2]  *  [-1, 0, 1]
[1]

在这里取外积会产生相同的矩阵。所以这里的想法是将操作分成两部分。首先将整个图像乘以行向量,然后乘以列向量。取行向量

-1 0 1

穿过图像,我们最终得到

2  2  2
2  2 -3
2 -3 -3

然后将列向量进行相乘和求和,我们再次得到

8, 3, -7

另一种巧妙的技巧可能有帮助,也可能没有帮助(取决于您在内存和效率之间的权衡):

请注意,在单行乘法中,您忽略中间的值,只需从左侧的值中减去右侧的值即可。这意味着您所做的实际上是减去这两个图像:

3 4 5     1 2 3
4 5 1  -  2 3 4
5 1 2     3 4 5

如果您从图像中删除前两列,您将得到左侧矩阵,如果您删除最后两列,您将获得右侧矩阵。所以你可以简单地计算卷积的第一部分

result_h = img[:,2:] - img[:,:-2]

然后您可以循环遍历索贝尔运算符的剩余列。或者,您甚至可以进一步进行,做我们刚刚做的同样的事情。这次对于垂直情况,您只需添加第一行和第三行以及第二行的两倍即可;或者,使用 numpy 加法:

result_v = result_h[:-2] + result_h[2:] + 2*result_h[1:-1]

你就完成了!我可能会在不久的将来在这里添加一些时间安排。对于一些粗略计算(即 1000x1000 图像上的仓促 Jupyter 笔记本计时):

新方法(图像总和):每次循环 8.18 ms ± 399 µs(7 次运行的平均值 ± 标准差,每次 100 次循环)

旧方法(双 for 循环):每个循环 7.32 s ± 207 ms(7 次运行的平均值 ± 标准差,每次 1 次循环)

是的,您没有看错:加速 1000 倍。


这是一些比较两者的代码:

import numpy as np

def sobel_x_orig(img):
    xKernel = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
    sobelled = np.zeros((img.shape[0]-2, img.shape[1]-2))
    for y in range(1, img.shape[0]-1):
        for x in range(1, img.shape[1]-1):
            sobelled[y-1, x-1] = np.sum(np.multiply(img[y-1:y+2, x-1:x+2], xKernel))
    return sobelled

def sobel_x_new(img):
    result_h = img[:,2:] - img[:,:-2]
    result_v = result_h[:-2] + result_h[2:] + 2*result_h[1:-1]
    return result_v

img = np.random.rand(1000, 1000)
sobel_new = sobel_x_new(img)
sobel_orig = sobel_x_orig(img)

assert (np.abs(sobel_new-sobel_orig) < 1e-12).all()

当然,1e-12是一些严重的公差,但这是每个元素的,所以应该没问题。但我也有一个float图像,你当然会有更大的差异uint8 images.

请注意,您可以这样做任何线性可分离滤波器!其中包括高斯滤波器。另请注意,一般来说,这需要大量操作。在 C 或 Fortran 或其他语言中,它通常只是实现为单行/列向量的两个卷积,因为最终它需要实际循环每个矩阵的每个元素;无论您只是将它们相加还是相乘,因此在 C 中将图像值相加并不比仅进行卷积更快。但循环遍历numpy数组非常慢,所以这个方法在 Python 中要快得多。

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

如何提高索贝尔边缘检测器的效率 的相关文章

  • goJS 下拉菜单删除项目

    我有简单的 python Flask goJS 图形应用程序 如下所示 节点和链接文本的源是从应用程序的后端加载的 我将它们设置为model modelData像这样的部分 var graphDataString JSON parse di
  • 如何在Python中找到低精度浮点值的原始文本表示?

    我遇到了显示问题floatPython 中的值 从外部数据源加载 它们是 32 位浮点数 但这也适用于较低精度的浮点数 以防万一 这些值是由人类在 C C 中输入的 因此与任意计算值不同 与round数字很 可能not预期的 但不能被忽略
  • 硒网格监听节点端口而不是集线器端口

    对于我的测试 我在不同的端口上本地运行网格和节点 java jar usr bin selenium server jar port 4444 role hub java jar usr bin selenium server jar ro
  • Flask - 如何从 JSON GET 请求获取参数

    我有一个发出以下 GET 请求的客户端 api GET tasks 5fe7eabd 842e 40d2 849e 409655e0891d 22task 22 22hello 22 22url 22 22 tasks 5fe7eabd 8
  • 如何在模型 Django 中创建必需:布尔字段

    我有一个模型 其中有一个名为的字段is student and is teacher Student and Teacher forms is teacher models BooleanField teacher status defau
  • Pyjnius导入jar文件

    Pyjnius 允许您为 java 类创建 python 包装器 例如 Hardware autoclass org myapp Hardware 有没有办法像这样导入现有的 jar 文件 语法是什么样的 您可以将 jar 添加到 CLAS
  • Django 和 AWS 简单电子邮件服务 [重复]

    这个问题在这里已经有答案了 我正在尝试启动并运行 django 站点 并且正在尝试启用 django 的标准密码重置服务 我的网站由 AWS EC2 托管 因此我想将 AWS SES 用于我的电子邮件服务 但是 我无法使 smtp 连接正常
  • Python绕相机轴旋转图像

    假设我有一个图像 是在对某些原始图像应用单应性变换 H 后获得的 未显示原始图像 将单应性 H 应用于原始图像的结果是该图像 我想围绕合适的轴 可能是相机所在的位置 如果有的话 将此图像旋转 30 度以获得此图像 如果我不知道相机参数 如何
  • Pandas cut 方法不包括下限

    我正在尝试对包含 0 到 100 范围内的年龄的数据帧列进行分箱 当我尝试使用垃圾箱来包含零年龄时 它不起作用 这是一个使用包含我的数据范围的列表的演示 pd cut pd Series range 101 0 24 49 74 100 范
  • PRAW 出现 SSLError?

    我正在尝试开始使用 PRAW 但在使用 login 时遇到问题 我有以下代码 import praw r praw Reddit This is a test bot r login myRedditUsername password 我收
  • 如何让 Discord 机器人显示“机器人正在输入...”状态?

    所以如果我有一个像这样的长命令 bot command pass context True async def longCommand ctx typing status sleep 10 bot say Done 不幸的是 在文档或此处没
  • 将Python嵌入到C中——导入模块

    我在使用嵌入式 Python for C 时遇到问题文档 http docs python org extending embedding html 每当我尝试使用导入的模块时 我都会得到 PythonIncl exe 中 0x1e089e
  • UTF-8 解码如何知道字节边界?

    我一直在阅读大量有关 unicode 编码的文章 尤其是有关 Python 的文章 我想我现在对此已经有了相当深入的了解 但仍有一个小细节我有点不确定 解码如何知道字节边界 例如 假设我有一个带有两个 unicode 字符的 unicode
  • 如何在Python中重命名virtualenv?

    我拼错了名字virtualenv使用以下方法初始化它 virtualenv vnev 我实际上打算创建一个名为的环境venv 尝试重命名后vnev文件夹到venv 我发现这并没有提供太多帮助 激活环境的名称仍然重命名旧的vnev mv vn
  • Tensorflow:Cuda 计算能力 3.0。所需的最低 Cuda 能力为 3.5

    我正在从源安装tensorflow 文档 https www tensorflow org versions r0 10 get started os setup html installing from sources Cuda驱动版本
  • 提取二值图像中的最中心区域

    我正在处理二进制图像 之前使用此代码来查找二进制图像中的最大区域 Use the hue value to convert to binary thresh 20 thresh thresh img cv2 threshold h thre
  • Odoo:如何覆盖原始功能

    在 Odoo 中 每次打开产品表单时都会计算产品的数量 这发生在模型中product product gt function product available 该函数返回一个名为 res 的字典 Example res 8 qty ava
  • Python:使用Excel CSV文件仅读取某些列和行

    虽然我可以读取 csv 文件而不是读取整个文件 但如何仅打印某些行和列 想象一下这是 Excel A B C D E State Heart Disease Rate Stroke Death Rate HIV Diagnosis Rate
  • 编写 CherryPy 装饰器以进行授权

    我有一个cherrypy应用程序 在某些视图上我想开始只允许某些用户查看它们 并将其他任何人发送到需要授权的页面 有没有办法使用自定义装饰器来做到这一点 我认为这将是最优雅的选择 这是我想做的一个基本示例 class MyApp autho
  • 如何找到 JAR:/home/hadoop/contrib/streaming/hadoop-streaming.jar

    我正在练习有关 Amazon EMR 的复数视角视频教程 我被困住了 因为我收到此错误而无法继续 Not a valid JAR home hadoop contrib streaming hadoop streaming jar 请注意

随机推荐

  • 哪种方式更好地创建 vue 组件(导出默认值、defineComponent 和新 Vue)

    最近学习 Vue js 后 我对如何编写 vue 组件语法感到非常困惑 我一直在看 YouTube 教程和文章 每个人都使用不同的方法 就 vue 3 而言 我们应该使用 导出默认值以创建组件 或导出默认的defineComponent 或
  • 远程连接到 SQL Server Express 实例

    尝试连接到远程 SQL Express 实例时 我收到以下错误 A network related or instance specific error occurred while establishing a connection to
  • 如何让网页自动改变宽度?

    在HTML中 有没有办法让网页扩展到用户的显示器 比如我有一个15英寸的 但别人有一个24英寸的 该网页在他们的屏幕上很小 但适合最小尺寸 如何使页面扩展至 100 或者 95 流体宽度是通过使用百分比单位或 em 单位来实现的 这一切都是
  • iOS 语音到数字格式的文本转换

    目前我正在使用默认的 iOS 语音到文本转换 而无需为其添加任何代码 当用户说 五 时 它会显示为 五 或 5 但是 我需要将它始终转换为 5 我可以使用 SFSpeechRecognizer 或任何其他方式来实现此目的吗 这可以帮助您入门
  • 将 const std::string & 作为参数传递的日子结束了吗?

    我最近听到赫伯 萨特 Herb Sutter 的一次演讲 他提出通过的理由std vector and std string by const 大部分已经消失了 他建议现在最好编写如下所示的函数 std string do somethin
  • Excel自动计算设置

    我在 Microsoft Office Excel 2007 中有一个复杂的项目 它使用了大量的 UDF 通过 VBA 在工作簿 打开事件 我将 Excel 自动计算设置为关闭 并策略性地放置计算每当我需要时手动计算单元格的方法 以便 UD
  • ggplot to png - 自动拉伸图像

    我正在生成一个ggplot plot并将其另存为 png图像 虽然 Rstudio 中生成的绘图根据 y 轴的值进行拉伸 但当我将其另存为时 我会得到一个正方形的图像 png 如何自动获得最佳拉伸图像 png form Function t
  • 微调器的“大”滚动条

    我有一个包含大量项目的旋转器 因此简单的滚动对于用户来说非常慢 我想在 ScrollView 中使用 大 可触摸滚动条或类似的滚动条 我该怎么做 我有一个装有大量物品的旋转器 这是你问题的一部分 将 Spinner 视为类似于桌面或 Web
  • 在 C# 中接受转义序列的 Label 属性 [重复]

    这个问题在这里已经有答案了 可能的重复 C 中标签是否有显示 的属性 我正在尝试在标签中显示客户姓名 当名称中存在任何 符号时 它会显示为 例如 A B XXX显示为AB with B下划线 除了硬编码之外 有什么办法可以显示 通过设置任何
  • 基于 n 元字符的相似性度量

    我使用以下代码从单词中提取了二元语法 Scanner a new Scanner file1 PrintWriter pw1 new PrintWriter file2 while a hasNext String gram a next
  • 在 CSS 中,当列表中有列表时,我无法覆盖父列表样式

    如果我有一个 列表 其中包含规则 list style type none 以及 项目的规则 background image url whatever jpg 我似乎看不到如果我有一个 列表作为其中一个 项目的子项 则覆盖这些规则 我想让
  • 如何使用 EXISTS 子句的正确方法

    在我的 SP 中 我正在创建一个临时表 PolicyNumbers并填充它Policy Numbers基于将提供给 SP 的参数 CREATE TABLE PolicyNumbers PolicyNumber varchar 50 INSE
  • Typescript,在 monorepo 项目中丢失 Zod 和 tRPC 类型,类型会导致任何

    我的处境有点奇怪 在过去的两周里 我一直在尝试调试为什么我在 monorepo 内的项目之间丢失类型 我的后端公开了我的客户端使用的类型 但由于某种原因 某些类型无法理解并成为any 这使得我有一段时间无法在这个项目上开发任何东西 我根据该
  • 如何确定c#中的dns变化?

    我想监控dns地址的变化 所以我需要跟踪 dns 更改 我现在正在用线程来做 我获取 dns 并将其保存为文件 然后每 10 秒比较一次它们 但我需要更具体的解决方案 例如 有相关活动吗 这是代码 GetDns public List
  • ReDim 下标超出范围 (VBA)

    您能否向我解释一下为什么这个简单的 VBA 代码在最后一行失败 下标超出范围 Dim test As Variant ReDim test 0 1 test 0 0 key test 0 1 1 ReDim Preserve test 1
  • Java 8 LocalDateTime 到日期丢失时区

    我有这个代码 我的系统的默认时区是 PDT 时区转换后 finalDate 显示 PDT 时间 如何让它显示 亚洲 新加坡 的最终日期 String strDate 201507081245 DateTimeFormatter mx3Dat
  • SSRS - 详细信息行中的垂直合并单元格

    我有一个存储过程 它返回一些数据 如下所示 Trade mode Area Production place Commodity Reseller Min sell price Max buy price Trans count Volum
  • Java JFrame 调整大小

    我知道我可以使用componentResized监听用户何时调整窗口大小 这不是一个很好的解决方案 如果我这样做并添加一个resize 子组件的方法 然后它会等到用户完成调整大小后再调用resize 方法 有没有办法在调整大小时调整子元素的
  • 断言列表中字段的唯一性

    我用 C 制作了一个列表 我想进行测试以查看 Id 字段的所有值是否都是唯一的 public static List
  • 如何提高索贝尔边缘检测器的效率

    我正在写一个计算机视觉库 https github com RoadKillCat PiCamVision从头开始使用 Python 来使用rpi相机 目前 我已经实现了转换为greyscale以及其他一些基本的img在我的设备上运行速度相