如果a,b是double类型,我如何在matlab中使用norm(a,b)?

时间:2014-08-15 15:59:05

标签: matlab norm

我必须使用angle = atan2(norm(cross(a,b)),dot(a,b))来计算两个向量a,b之间的角度,这些是双重类型,norm未定义此类型。我该如何解决这个问题?我需要以这种方式计算两个矢量之间的角度。

2 个答案:

答案 0 :(得分:1)

在您的评论中,您向我们展示了您实际上是如何写出角度计算的,这与您将其放入帖子的方式不同。

atan2(norm(cross(I(i,j,:),I_avg)),dot(I(i,j,:),I_avg));

I是您要加载的图片。由于您正在对I进行子集化,我假设它的颜色。因为I是一个3D矩阵,所以I(i,j,:)会给你一个1 x 1 x 3向量,而实际上它必须是一维向量。 norm无法识别此结构,这就是您收到此错误的原因。因此,您需要使用squeeze删除单例维度,以便它将成为3 x 1向量,而不是1 x 1 x 3向量。因此,您需要重写代码,以便您反而执行此操作。请记住,在您的评论中,angle循环中始终会覆盖for,因此您可能希望保存每个像素的结果。有了这个,您可能想要创建一个存储这些结果的2D角度数组。换句话说:

I=imread('thesis.jpg'); 
I = double(I);
angles = zeros(m,n);
I_avg = squeeze(I_avg); %// Just in case 
for i=1:m 
    for j=1:n 
        pixels = squeeze(I(i,j,:)); %// Add this statement and squeeze
        angles(i,j) = atan2(norm(pixels,I_avg)),dot(pixels,I_avg)); %// Change
    end 
end

次要说明

MATLAB有一个名为angle的内置函数,用于确定复杂平面中从原点到复数的角度。我们不建议您调用变量angle,因为这会无意中影响angle函数,而您从此时开始创建的任何其他代码都可能依赖于实际的angle函数,你会得到意想不到的结果。

另一个小调

不建议使用ij作为循环变量。这些字母是为复数保留的,这可能会产生无意的结果。请查看此问题,然后在Shai点{ - 3}}发帖。因此,建议您改用其他变量名称。

答案 1 :(得分:1)

由于@rayryeng已经成功回答了这个问题,我想通过分享我在Matlab中调试的经验,将我的帖子变成更一般的帖子。我希望任何以某种方式设法找到这篇文章的人都会或多或少地想到一个优秀的程序员应该拥有的习惯。

问题是:"如果我收到错误,我该怎么办?"

  1. 这里有an excellent article by Eric,当你遇到一个错误并希望摆脱它时,他列出了拇指规则。它最初是由Stackoverflow引用的,这就是我阅读它的原因。

  2. 如果您仍然不知道如何使用代码,请查看此人的行为:

  3. 确定错误线

    1. (数字应以0开头)确保在运行脚本之前,clear输出任何先前存储的变量,包括the notorious i and j's (you should never see them in any workspace)。如果要运行错误代码需要任何一个,clear之前save('buggy.mat','importantvar')load('buggy.mat')之后清除。

      通过这样做,您可以将您的错误代码与其他任何可能产生不良影响的代码隔离开来。例如,在之前调用的脚本中,有一行

      double = [2,4,6]; % you should never name a variable `double`
      

      在下一个脚本中,你有

      >> e = str2num('uint8(200)')
      e =
        200
      >> double(e)
      Index exceeds matrix dimensions. 
      >> 
      >> f = single(2.36)
      f =
          2.3600
      >> double(f)
      Subscript indices must either be real positive integers or
      logicals. 
      >> 
      

      原因是double不再是an inbuild function,而是用户定义的变量。不小心拿起一个名字太糟糕了!

      ....无论如何,让我们clear工作区并摆脱double

      >> clear
      
    2. 阅读错误消息彻底

      现在让我们从OP的问题开始吧。原始代码(修剪过)就像这样 -

      img = imread('peppers.png');
      a = img(300,200,:);
      b = img(200,300,:);
      d = norm(cross(a,b));
      

      ....因此错误

      Undefined function 'norm' for input arguments of type 'uint8'.
      Error in untitled (line 6)
      d = norm(cross(a,b)); 
      

      大多数初学者只对错误信息的第一行感兴趣,因为它本身通常不能提供任何有用的帮助,或者只是红色,这导致着名的问题" my代码不起作用!"

      三思而后行。你还有另外两行未读! Error in untitled (line 6)说我正在运行名为untitled的脚本,而(第一个)错误位于第6行,该行中的代码为d = norm(cross(a,b));

      现在,至少你对代码有了更多了解 - "我的代码d = norm(cross(a,b));无效!"

      虽然我们很可能也会投票支持这类问题,但它仍然比简单的&#34更好!它不起作用!"。

    3. 现在我们可以指出有缺陷的线

      try
      %     this line will raise an error
          d = norm(cross(a,b));
      catch err
          disp(err.message)
      end
      
    4. 查看函数

      首先,确保内部函数cross按预期工作 -

          >> cross(a,b)
          ans(:,:,1) =
              0
          ans(:,:,2) =
            255
          ans(:,:,3) =
              0
          >> 
      

      好。所以现在我们甚至可以将错误范围缩小到外部norm

      还有一件事需要提及。你总能找到Mathworks' 任何 in-build功能的文档,通过键入" matlab function ",例如" matlab norm"在Google(或任何其他搜索引擎)中点击第一个结果。如果您愿意,还可以输入Matlab命令窗口doc _function_,例如doc norm,并阅读Matlab中的文档。当然,我们很高兴Stackoverflow能够通过做同样的事情为您提供参考,但它需要更长的时间,因为在这方面,人类总是比搜索引擎慢。

      错误显示为Undefined function 'norm' for input arguments of type 'uint8'.。因此norm的输入不应该是uint8,无符号的8位整数。但它应该是什么?

      % why `norm` "does not work"? 
      % this line runs perfectly well
      norm(cross([1,2,3], [4,5,6]))
      % so what is working? 
      class([1,2,3]) % so `norm` works for `double`
      

      我们现在可以做的一件事是将ab转换为双精度。我们现在试试吧。

      % try fixing 'uint8' error
      a2 = double(a);
      b2 = double(b);
      whos a b % now they are double, which `norm` should work for
      try
      %     this line will raise an error
          d = norm(cross(a2,b2));
      catch err
          disp(err.message)
      end
      

      现在错误变为Input must be 2-D.。输入有什么问题?

      % what is "must be 2-D" error? 
      size(a2) % a2 is 3-D
      disp(b2) % b2 is also 3-D
      

      这在命令窗口中输出

      ans =
           1     1     3
      (:,:,1) =
         255
      (:,:,2) =
         150
      (:,:,3) =
           0
      

      在OP的问题中,他/她正试图计算一些关于色差(据我所知)在RGB空间中涉及the angle between two color vectors的事情。所以需要矢量。对于imread,图像的每个像素在矩阵中存储为3个元素,第一维2是其物理位置,3维是RGB通道分量。因此,具有颜色rgb [255,150,0]的像素(200,300)由我们存储在变量b中,其中是3-D向量。

      通过了解我们需要什么 Matlab可以做什么,我们可以将这两点合并为一个。我们需要ab的叉积的范数,而有用信息(3个组件值)存储在第三维中。 Matlab可以计算向量的叉积的范数及其在第一维中的所有信息。 (这里,"尺寸"指的是Matlab变量的尺寸;第一维中具有3个元素的矢量在物理上是3-D矢量)。

      在考虑了两次之后,我们现在可以调试我们的代码 - 只需将所有3个元素放入第一维。

      % so we want the 3 elements in the 3rd dimension become in the 1st dim
      a3 = squeeze(a2);
      b3 = reshape(b2,numel(b2),[]);
      try
          d = norm(cross(a3,b3));
      catch err
          disp(err.message)
      end
      d
      

      Bonus:如果默认情况下Matlab将3-D向量视为" 1-D数组",则很可能cross函数无法正常工作。我们来检查一下 -

      >> clear
      >> a = [1,2,3]
      a =
           1     2     3
      >> b=[4,5,6]
      b =
           4     5     6
      >> cross(a,b)
      ans =
          -3     6    -3
      >> 
      

      结果应该与我们手工计算得到的结果相同。

      现在,如果我们将组件放入变量的第三维 -

      >> clear
      >> a(1,1,:)=[1,2,3]
      a(:,:,1) =
           1
      a(:,:,2) =
           2
      a(:,:,3) =
           3
      >> b(1,1,:)=[4,5,6]
      b(:,:,1) =
           4
      b(:,:,2) =
           5
      b(:,:,3) =
           6
      >> cross(a,b)
      ans(:,:,1) =
          -3
      ans(:,:,2) =
           6
      ans(:,:,3) =
          -3
      >> 
      

      ....似乎没问题。 cross也将结果放在第三维。事实上,Mathworks'文件说

        

      如果A和B是向量,则它们的长度必须为3。

           

      如果A和B是矩阵或多维数组,那么它们必须   具有相同的大小。在这种情况下,交叉函数将A和B视为   三元素向量的集合。该函数计算   沿第一阵列维度的相应向量的交叉乘积   其大小等于3。

      最后,对于任何想要编程的人来说,有一件事总是正确的 - 在编写代码时要谨慎谨慎。