opencv中矩阵的超快中值(与matlab一样快)

2024-05-06

我正在 openCV 中编写一些代码,想要找到一个非常大的矩阵数组(单通道灰度、浮点数)的中值。

我尝试了几种方法,例如对数组进行排序(使用 std::sort)和选择中间条目,但与 matlab 中的中值函数相比,它非常慢。准确地说,在 matlab 中需要 0.25 秒的事情在 openCV 中需要 19 秒以上。

我的输入图像最初是尺寸为 3840x2748(约 10.5 兆像素)的 12 位灰度图像,转换为浮点数(CV_32FC1),其中所有值现在都映射到范围 [0,1],并且在代码中的某个点我通过调用以下命令请求中值:

double myMedianValue = medianMat(Input);

其中函数 MedianMat 为:

double medianMat(cv::Mat Input){    
    Input = Input.reshape(0,1); // spread Input Mat to single row
    std::vector<double> vecFromMat;
    Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat    
    std::sort( vecFromMat.begin(), vecFromMat.end() ); // sort vecFromMat
        if (vecFromMat.size()%2==0) {return (vecFromMat[vecFromMat.size()/2-1]+vecFromMat[vecFromMat.size()/2])/2;} // in case of even-numbered matrix
    return vecFromMat[(vecFromMat.size()-1)/2]; // odd-number of elements in matrix
}

我对函数 medinaMat 本身以及各个部分进行了计时 - 正如预期的那样,瓶颈在于:

std::sort( vecFromMat.begin(), vecFromMat.end() ); // sort vecFromMat

这里有人有有效的解决方案吗?

Thanks!

EDIT我尝试过使用 Adi Shavit 的答案中给出的 std::nth_element 。

函数 MedianMat 现在读作:

double medianMat(cv::Mat Input){    
    Input = Input.reshape(0,1); // spread Input Mat to single row
    std::vector<double> vecFromMat;
    Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat
    std::nth_element(vecFromMat.begin(), vecFromMat.begin() + vecFromMat.size() / 2, vecFromMat.end());
    return vecFromMat[vecFromMat.size() / 2];
}

运行时间从 19 秒以上缩短至 3.5 秒。这仍然远低于 Matlab 中使用中值函数的 0.25 秒......


排序并取中间元素并不是查找中位数的最有效方法。它需要 O(n log n) 次操作。

对于 C++ 你应该使用std::nth_element() http://en.cppreference.com/w/cpp/algorithm/nth_element并取中间的迭代器。这是一个 O(n) 操作:

nth_element is a 部分排序重新排列元素的算法[first, last)这样:

  • 所指向的元素nth更改为该位置会出现的任何元素if [first, last)已排序.
  • 这个新的第 n 个元素之前的所有元素都小于或等于新的第 n 个元素之后的元素。

另外,您的原始数据是 12 位整数。您的实现做了一些事情,导致与 Matlab 的比较出现问题:

  1. 您转换为浮点数(CV_32FC1或双精度或两者),这是昂贵的并且需要时间
  2. 该代码有一个额外的副本vector<double>
  3. 对浮点数(尤其是双精度数)的运算比对整数的运算成本更高。

假设您的图像在内存中是连续的,这是您应该使用的 OpenCV 的默认值CV_16C1,然后直接处理数据数组reshape()

另一个应该非常快的选择是简单地构建图像的直方图 - 这是图像上的单次传递。然后,处理直方图,找到对应于每侧一半像素的箱 - 这最多是一次通过bins.

OpenCV 文档有several http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html#histogram-calculation 教程 http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.html#histogram-equalization on http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.html#histogram-comparison如何构建直方图。获得直方图后,累积 bin 值,直到达到 3840x2748/2。这个垃圾箱是你的中位数。

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

opencv中矩阵的超快中值(与matlab一样快) 的相关文章

  • R中将矩阵拆分为子矩阵的函数

    我有一个 16 行 12 列的矩阵 M 我想将其拆分为 16 个矩阵的数组 每个矩阵有 4 行 3 列 我可以通过以下方式手动完成 M matrix sample 0 127 16 12 replace TRUE c 16 12 ma1 M
  • 全局变量不好

    好吧 读完这篇文章和一些示例后 我仍然不清楚全局变量的含义 那么你的类中的私有变量是全局的吗 http www c2 com cgi wiki GlobalVariablesAreBad http www c2 com cgi wiki G
  • 处理器关联组 C#

    我使用的是 72 核的 Windows Server 2016 我看到有两组处理器 我的 net 应用程序将使用一个或其他组 我需要能够强制我的应用程序使用我选择的组 我看到下面的代码示例 但我无法使其工作 我可能传递了错误的变量 我希望应
  • 为类型列表创建别名并将其作为模板参数传递

    我正在使用可变参数模板来实现访问者模式 template
  • 字符串/分段错误

    Program to calculate trip and plan flights define TRIP 6 define NAMEMAX 40 define DEST 1 include
  • 如何反序列化 XML 文档

    如何反序列化此 XML 文档
  • 如何在 Google Mock 中使用可选参数来模拟方法?

    如何使用可选参数模拟方法谷歌模拟 例如 class A public void set enable bool enabled true class MockA public A MOCK METHOD1 set enable void b
  • 以编程方式更新 Wifi 网络

    我正在尝试创建一个程序 当某个 wifi 网络在范围内时 该程序会连接到该网络 即使已经连接到另一个 wifi 也是如此 我在用着简单Wifi https github com DigiExam simplewifi 基本上效果很好 除了在
  • R 包与 Rcpp 的链接错误:“未定义符号:LAPACKE_dgels”

    我正在创建一个 R 包 lapacker 以使用 R API 头文件 R ext Lapack h 为 R 提供和使用的内部 LAPACK 库 仅具有双精度和双复数 提供 C 接口 源代码 https github com ypan1988
  • .Net 支持柯里化泛型吗?

    假设我们有一个嵌套的泛型类 public class A
  • 大小为 k 的非连续子序列的最大值的最小值

    在开始之前 我希望这个问题不是重复的 我发现了几个类似的问题 但它们似乎都没有描述完全相同的问题 但如果它是重复的 我会很高兴看到一个解决方案 即使它与我的算法不同 我一直在尝试回答这个问题 https stackoverflow com
  • 如何使用 itextsharp 更改 PDF 公式的按钮图标?

    我目前正在尝试使用 itextsharp 填写预定义的表单 除了添加图像之外 一切正常 这之前已经在 Adob e 的 FDF 工具包中运行过 该工具包已编译为 NET 1 1 这不再适用于 NET 4 0 我改用了 itextsharp
  • 括号内声明的对象的范围

    如果我声明一个这样的对象 void main myclass objectA anotherclass true true 0 即 我通过直接调用后者的构造函数来创建一个 objectA 和另一个对象 anotherclass anothe
  • 在 OSX 上检测 Objective C 或 C++ 中的文件夹访问(如 fs_usage 命令)

    我正在 OSX 上开发实时病毒扫描程序 OSX 的命令行命令fs usage可以通过以下方式确定文件夹访问权限 并且只能以 root 用户身份运行 fs usage w f pathname grep Users Documents Use
  • Microsoft Visual Studio 2017 中的 wxWidgets 设置

    我花了大约 20 个小时试图弄清楚如何在 Microsoft Visual Studio 2017 中设置 wxWidgets 我遵循 https wiki wxwidgets org Microsoft Visual C 2B 2B Gu
  • C# 中的 mshtml.HTMLDocumentClass

    在 C 中 我设法从 InternetExplorer 对象获取整个 HTMLDocumentClass 导航到某个 URL 然而 在 Visual Studio 2008 的调试模式下 该特定 URL 的 HTMLDocumentClas
  • 使用属性和性能

    我正在优化我的代码 我注意到使用属性 甚至自动属性 对执行时间有深远的影响 请参阅下面的示例 Test public void GetterVsField PropertyTest propertyTest new PropertyTest
  • 在for循环中声明和初始化变量

    可以简单写一下吗 for int i 0 代替 int i for i 0 在 C 或 C 中 并且会变量i只能在循环内部访问 它在 C 中有效 它在 C 的原始版本中是不合法的 但在 C99 中被采用为 C 的一部分 当时一些 C 功能被
  • 如何正确处置注入的DLL线程?

    我将一个 DLL 注入到目标进程中 以在玩 MMORPG 时充当助手 当前功能将按键转换为鼠标点击 因为 MMORPG 要求用户移动鼠标才能实现某些功能 这是我所鄙视的 假设我出于某种原因想要取消注入 DLL 我该怎么做呢 这个方法干净吗
  • Web 和 winforms 的 .Net 身份验证

    我有一个为客户端构建的 ASP NET Web 应用程序 它使用默认的 ASP NET 表单身份验证 他们现在请求一个能够 与 Web 应用程序一起工作的桌面 WinForms 应用程序 我已经创建了 Web 服务来访问他们想要从 Web

随机推荐