【问题标题】:Use imfilter (matlab) in C++在 C++ 中使用 imfilter (matlab)
【发布时间】:2020-12-28 19:32:44
【问题描述】:

我有一个带有 imfilter 的 matlab 代码。现在我想将其转换为 C++。我读了这个here 但我无法使用 openCV3.3 实现 filterEngine(不再有 filterEngine)。

也就是matlab中的过滤器:

imfilter(im2double(image),k,'same','replicate');

那是我的内核k:

k = fspecial('disk',3)

这一行的结果是一个 7x7 矩阵,其值介于 0 - 1 之间。

所以过滤器得到一个输入图像。它的值介于 0 和 1 (im2double) 之间。所以我必须将我的 8bit 图像转换为这个范围,我认为它的工作原理是这样的:

cv::normalize(inImage,outImage,0,1,cv::NORM_MINMAX);

然后用内核过滤图像。 最后我想再次输出一个8bit的图像。

所以我想将两个给定的 Matlab 行转换为 C++。

我在链接中读到您不能简单地使用 filter2D。 但我该怎么做?有人有想法吗?

++++编辑++++(测试zteffi的代码sn-p)

我已经测试了代码。到目前为止,结果是不同的。

内核“磁盘”的结构有点不同(更多的零)。其中的值也与Matlab中的不同。

Matlab 内核:

0   0.000280919186665314    0.0110250278796606  0.0171905962763014  0.0110250278796606  0.000280919186665314    0
0.000280919186665314    0.0245167426505023  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0245167426505023  0.000280919186665314
0.0110250278796606  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0110250278796606
0.0171905962763014  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0171905962763014
0.0110250278796606  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0110250278796606
0.000280919186665314    0.0245167426505023  0.0353677651315323  0.0353677651315323  0.0353677651315323  0.0245167426505023  0.000280919186665314
0   0.000280919186665314    0.0110250278796606  0.0171905962763014  0.0110250278796606  0.000280919186665314    0

c++内核:

[0, 0, 0, 0.0303030303030303, 0, 0, 0;
 0, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0;
 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303;
 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303;
 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303;
 0, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0.0303030303030303, 0;
 0, 0, 0, 0.0303030303030303, 0, 0, 0]

我不知道matlab中的值是怎么计算出来的。

以下行应在 tha 矩阵中创建一个值“圆圈”。 但在行维度中,边缘有 3*2 个零,而在列维度中有 2 *2 个零。但是每个角应该只有一个零。

Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(radius * 2 + 1, radius * 2 + 1));

【问题讨论】:

  • 所以这还不够接近,但之前你回复了一个答案,“imfilter 有超过 400 行代码。这个问题的努力太高了。我认为获得接近原始过滤器的结果是可以的。”做什么是什么?类似的东西很容易,或者更接近的东西很难?还是您希望其他人为您实现此功能???
  • 不,没有人需要为我实现。当我在这里看到其他贡献时,我总觉得很多人都知道答案,而无需自己编写太多程序。(仅凭经验)我希望如此。我不想对这里的任何人造成太大的影响
  • 我现在对内核进行了硬编码,没关系
  • Matlab 的版本使用抗锯齿圆。您可以尝试 OpenGL 或其他一些库。不幸的是,cv::circle 即使使用cv::LineTypes::LINE_AA 标志也不起作用
  • Wolfus,对内核进行硬编码是一个很好的解决方案。

标签: c++ matlab opencv filter


【解决方案1】:

fspecial('disk',3) 的等价物是 cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(radius * 2 + 1, radius * 2 + 1)),除以内核的总和,所以总和等于 1。所以类似于:

Mat m = cv::imread("lena.jpg");
int radius = 3;
Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(radius * 2 + 1, radius * 2 + 1));
double sum = cv::sum(cv::sum(kernel))[0]; // use cv::sum twice to get sum of all elements
kernel.convertTo(kernel, CV_64F, 1 / sum);
cv::filter2D(m, m, CV_64F, kernel);
m.convertTo(m, CV_8U);

除非需要显示,否则不需要将图像转换为 范围。在这种情况下,您也不需要将其转换为 double 并将最后两行交换为:

cv::filter2D(m, m, CV_8U, kernel);

【讨论】:

  • 我会在接下来的几天里测试它——谢谢你的回答!
  • 感谢您的帮助!我测试了您的代码,但结果不同。我用结果编辑了我的原始帖子
  • 为什么要使用 CV_64F - 这不是太大了吗?或者这还有其他好处吗?
  • 我认为CV_64FCV_32F 之间的精度差异在这种情况下不会很明显,我使用双精度来匹配matlab。
【解决方案2】:

你可以通过在编辑器中的函数名称上单击鼠标右键并在菜单中选择“打开'函数名称'”项来查看matlab的函数实现。它将显示该函数的 matlab 代码,您可以将其准确地移植到 C++。

【讨论】:

  • 这不是我想要的——im 过滤器有超过 400 行代码。这个问题的努力太高了。我认为得到接近原始过滤器的结果是可以的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
  • 2021-11-17
  • 1970-01-01
  • 1970-01-01
  • 2018-05-02
相关资源
最近更新 更多