【问题标题】:How to apply element-wise operations without using for loops and without influencing the speed如何在不使用 for 循环且不影响速度的情况下应用元素操作
【发布时间】:2013-06-24 09:39:59
【问题描述】:

假设我有一个 RGB 图像矩阵,我想在其上应用一些空间过滤器。 一般来说,我想应用元素操作(请注意,这是一项大学作业,我不允许使用图像处理工具箱中提供的任何内置函数)。我决定将过滤器编写为函数,然后将bsxfun 应用于图像上的这些函数。

一个简单的例子是:
我想将 50 添加到图像的所有灰度级,然后用 200 替换所有高于 200 的灰度级。这是我的代码:

a='C:\Users\sepideh\Desktop\IP_abadpour\S45C-113050518040.jpg';  
b=imread(a);  
b(:,:,1)=b(:,:,1)+50;  
b(:,:,2)=b(:,:,2)+50;  
b(:,:,3)=b(:,:,3)+50;  
c=reshape(b,[],1);  
d=bsxfun(@test,c,200);

test 是这种形式的函数:

function Out = test(in,a)  
   if in>a
      in=200;
   end
   Out = in;
end  

此代码不起作用,因为在第二行中,“in > a”是一个包含 0 和 1 的矩阵(我的意思是所有元素都不是 1,也不应该是),因此调试器不会分支到if 声明。

您能否指导我如何编写此函数以及如何在图像上应用空间和傅立叶分析,而不影响性能和运行时速度?

【问题讨论】:

    标签: performance matlab image-processing filter bsxfun


    【解决方案1】:

    这里有几个建议:

    1. 首先,您不需要将 50 单独添加到 RGB 矩阵的每一层。你可以这样做:

      b = b + 50;
      
    2. 为什么在将b 传递给bsxfun 之前对其进行整形? bsxfun 的输出大小和你的图片一样,这里真的没必要再整形了。

    3. 关于您的 test 函数,请注意 official documentation of bsxfun 的说明:

      C = fun(A,B) 形式的二进制逐元素函数接受任意但大小相等的数组 AB,并返回相同大小的输出。输出数组C 中的每个元素都是对AB 的对应元素进行运算的结果。 fun 还必须支持标量扩展,这样如果AB 是标量,C 就是将标量应用于另一个输入数组中的每个元素的结果。

      所以bsxfun 执行单例扩展并将其两个输入数组“膨胀”到相同的大小,然后将指定的函数应用于膨胀的数组。逐元素函数fun 实际上是在数组上运行,而不是在标量上运行。我没有看到在这里使用bsxfun 有任何实际好处。

      也就是说,您可以按照Dan 的建议简化代码,或者将其实现为函数:

      function out = test(in, a);
          out = in;
          out(in > a) = a;
      

      我假设如果您使用值 210 而不是 200,那么您也希望使用 210 来限制所有灰度级,因此您确实应该使用 a 而不是硬编码的值 200。您也可以像这样编写你的函数:

      function out = test(in, a)
          out = min(in, a);
      

      然后调用它:

      d = test(b, 200);
      

      而不是更复杂的d = bsxfun(@test, b, 200)

      另一种选择是使用arrayfun

      d = arrayfun(@(x)test(x, 200), a);
      

      d = arrayfun(@test, a, 200 * ones(size(a)));
      

      其中arrayfun 将按元素应用test,而test 函数只需要对标量进行操作。但是,arrayfun 通常运行速度比循环慢,更不用说矢量化操作了。

    4. 对于空间分析,请查看conv2,就像建议的Dan 一样(或实现自己的二维卷积,以方便练习)。对于傅立叶分析,请考虑在频域中使用fft2ifft2 函数。

    希望这会有所帮助!

    【讨论】:

    • 嗯,你建议的函数运行良好,除了 max 函数应该被 min 替换。但另一个问题出现了。为什么我的功能不起作用。我的意思是,如果您在函数中停止调试器,您会看到“in”不是标量,而是在调用测试时的矩阵,并且您说:您的函数没有任何问题,因为它当前是可写的??!!! !!
    【解决方案2】:

    因此,对于您发布的示例,您可以利用 matlab 中的大多数运算符原生地处理矩阵这一事实:

    b=imread(a);
    c = a + 50;
    c(c > 200) = 200;
    

    就这么简单。

    对于过滤,如果允许,我会看看conv2 函数。您可以通过这种方式进行空间滤波,而无需转换到频域(请记住,频域中滤波器的乘法与空间域中的卷积相同)。例如一个基本的低通滤波器:

    lpf = ones(5)./25;
    c(:,:,1) = conv2(b(:,:,1), lpf);
    c(:,:,2) = conv2(b(:,:,2), lpf);
    c(:,:,3) = conv2(b(:,:,3), lpf);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-26
      • 2016-04-20
      • 2012-04-18
      • 2018-03-21
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      相关资源
      最近更新 更多