Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何在Matlab中加速我的代码[包括示例]?_Algorithm_Performance_Matlab_Image Processing - Fatal编程技术网

Algorithm 如何在Matlab中加速我的代码[包括示例]?

Algorithm 如何在Matlab中加速我的代码[包括示例]?,algorithm,performance,matlab,image-processing,Algorithm,Performance,Matlab,Image Processing,我想加速我的代码。目前,我使用if语句来做这件事。但是,如果我们使用的是。然而,它只适用于简单情况(如成对邻域)。让我们来定义我的问题 我有一个矩阵I=[1 1;2 2;2 2 1],它有两个标签{1,2}。我在右边加了填充物。对于I中的每个像素,我们可以定义一对或三对邻域。我们将根据规则检查“如果这些邻域值与像素具有相同的类别,则将成本值设置为等于-beta,否则将成本设置为等于beta” 例如,让我们考虑上面的黄色像素,它的标签是2。我们需要计算可能的邻域情况下的总成本值,如最右边所示。将

我想加速我的代码。目前,我使用if语句来做这件事。但是,如果我们使用的是。然而,它只适用于简单情况(如成对邻域)。让我们来定义我的问题

我有一个矩阵
I=[1 1;2 2;2 2 1]
,它有两个标签
{1,2}
。我在右边加了填充物。对于
I
中的每个像素,我们可以定义一对或三对邻域。我们将根据规则检查“如果这些邻域值与像素具有相同的类别,则将成本值设置为等于
-beta
,否则将成本设置为等于
beta

例如,让我们考虑上面的黄色像素,它的标签是2。我们需要计算可能的邻域情况下的总成本值,如最右边所示。将从标签{1,2}设置感兴趣像素的值。在上图中,我只展示了将黄色像素设置为1的第一种情况。我们可以有相同的数字,但设置黄色像素是2为下一种情况。我的任务是根据上述规则计算成本函数

这是我的密码。但是,它使用if语句。太慢了。你能帮我加快速度吗?我试着用卷积的方法,但我不知道如何定义一个三重邻域的掩码。谢谢大家

function U=compute_gibbs(Imlabel,beta,num_class)
num_class=2;
Imlabel=[1 1 1;2 2 2;2 2 1]
beta=1;
U=zeros([size(Imlabel) num_class]);
Imlabel = padarray(Imlabel,[1 1],'replicate','both');
[row,col] = size(Imlabel);
for ii = 2:row-1        
    for jj = 2:col-1
        for l = 1:num_class
            U(ii-1,jj-1,l)=GibbsEnergy(Imlabel,ii,jj,l,beta);
        end
    end
end
function energy = GibbsEnergy(img,i,j,label,beta)
    % img is the labeled image
    energy = 0;
    if (label == img(i,j)) energy = energy-beta;
        else energy = energy+beta;end        
    % North, south, east and west
    if (label == img(i-1,j)) energy = energy-beta;
        else energy = energy+beta;end
    if (label == img(i,j+1)) energy = energy-beta;
        else energy = energy+beta;end
    if (label == img(i+1,j)) energy = energy-beta;
        else energy = energy+beta;end
    if (label == img(i,j-1)) energy = energy-beta;
        else energy = energy+beta;end
    % diagonal elements
    if (label == img(i-1,j-1)) energy = energy-beta;
        else energy = energy+beta;end
    if (label == img(i-1,j+1)) energy = energy-beta;
        else energy = energy+beta;end
    if (label == img(i+1,j+1)) energy = energy-beta;
        else energy = energy+beta;end
    if (label == img(i+1,j-1)) energy = energy-beta;
        else energy = energy+beta;end
     %% Triangle elements
    % Case a 
    if(label==img(i-1,j)&label==img(i-1,j-1)) energy = energy-beta;
        else energy = energy+beta;end 
    if(label==img(i,j-1)&label==img(i+1 ,j)) energy = energy-beta;
        else energy = energy+beta;end
    if(label==img(i,j+1)&&label==img(i+1 ,j+1)) energy = energy-beta;
        else energy = energy+beta;end 
    % Case b 
    if(label==img(i-1,j-1)&label==img(i,j-1)) energy = energy-beta;
        else energy = energy+beta;end     
     if(label==img(i-1,j)&label==img(i ,j+1)) energy = energy-beta;
        else energy = energy+beta;end  
     if(label==img(i+1,j)&label==img(i+1,j+1)) energy = energy-beta;
         else energy = energy+beta;end  
    % Case c   
    if(label==img(i,j-1)&label==img(i+1,j-1)) energy = energy-beta;
         else energy = energy+beta;end  
    if(label==img(i+1,j)&label==img(i,j+1)) energy = energy-beta;
         else energy = energy+beta;end  
    if(label==img(i-1 ,j)&label==img(i-1,j+1)) energy = energy-beta;
        else energy = energy+beta;end 
    % Case d 
    if(label==img(i,j-1)&label==img(i-1,j)) energy = energy-beta;
        else energy = energy+beta;end 
    if(label==img(i-1 ,j+1)&label==img(i,j+1)) energy = energy-beta;
        else energy = energy+beta;end 
     if(label==img(i+1,j-1)&label==img(i+1 ,j)) energy = energy-beta;
        else energy = energy+beta;end 

    %% Rectangular
    if(label==img(i-1,j-1)&label==img(i,j-1)&label==img(i-1 ,j)) energy = energy-beta;
        else energy = energy+beta;end 
    if(label==img(i,j-1)&label==img(i+1,j-1)&label==img(i+1 ,j)) energy = energy-beta;
        else energy = energy+beta;end 
     if(label==img(i+1,j)&label==img(i +1 ,j+1)&label==img(i,j+1)) energy = energy-beta;
        else energy = energy+beta;end 
     if(label==img(i-1,j)&label==img(i-1,j+1)&label==img(i ,j+1)) energy = energy-beta;
        else energy = energy+beta;end 
这是一种更快的方法。但它只适用于简单情况(成对邻域第一行),而我的情况包括单邻域、三邻域

C = double(bsxfun(@eq, Imlabel, permute(1:num_class, [1 3 2])));
C(C == 0) = 0;
C(C == 1) = beta;
%% Replace if statement
mask = zeros(3,3); mask(2,2) = 1;
Cpad = convn(C, mask);
Cpad(Cpad == 0) = 0;

mask2 = ones(3,3); mask2(2,2) = 0;
energy = convn(Cpad, mask2, 'valid');

以下是我在这方面的尝试。我真的不知道哪一个对你来说会更快,因为我使用的是倍频程而不是MATLAB,而且计时可能会有很大的不同。例如,
For
循环仍然以八度持续。你必须测试它们,看看它们是如何比较的

矩阵乘法 例如,一种方法是使用矩阵乘法。如果你选择一个3x3的社区,比如

nbr = [0 0 0;
       1 0 0;
       1 1 0];
如果您想知道左上角的元素是否为
1
,则可以通过掩码执行元素相乘

mask = [1 0 0;
        0 0 0;
        0 0 0];

result = sum(mask .* nbr);
(我在这里选择了一个捷径,假设邻域是一个二进制矩阵。当我得到实际代码时,我将简单地使用
nbr==current_class
来实现这一点。)

如果结果具有与掩码相同数量的
1
元素,则获得了匹配项。在这种情况下,这两个的元素相乘都是零,因此不匹配

我们可以将
nbr
mask
转换为向量,并使用向量乘法,而不是先进行元素乘法,然后对结果的元素求和:

m = mask(:).';
n = nbr(:);
result = m * n;
这将为您提供与上一个结果相同的值。如果你有一个掩模矩阵,你可以用它乘以邻域向量,然后一次得到所有的结果。因此,第一步是生成25个掩模向量:

masks = [
   0   0   0   0   1   0   0   0   0;
   0   0   0   0   0   1   0   0   0;
   0   0   0   1   0   0   0   0   0;
   0   0   0   0   0   0   0   1   0;
   0   1   0   0   0   0   0   0   0;
   1   0   0   0   0   0   0   0   0;
   0   0   0   0   0   0   0   0   1;
   0   0   0   0   0   0   1   0   0;
   0   0   1   0   0   0   0   0   0;
   1   1   0   0   0   0   0   0   0;
   1   0   0   1   0   0   0   0   0;
   0   0   0   1   0   0   1   0   0;
   0   0   0   0   0   0   1   1   0;
   0   0   0   0   0   0   0   1   1;
   0   0   0   0   0   1   0   0   1;
   0   0   1   0   0   1   0   0   0;
   0   1   1   0   0   0   0   0   0;
   0   0   0   1   0   0   0   1   0;
   0   0   0   0   0   1   0   1   0;
   0   1   0   1   0   0   0   0   0;
   0   1   0   0   0   1   0   0   0;
   1   1   0   1   0   0   0   0   0;
   0   0   0   1   0   0   1   1   0;
   0   0   0   0   0   1   0   1   1;
   0   1   1   0   0   1   0   0   0];
现在,当你将
蒙版
乘以邻域时,你可以一次得到所有结果。然后将结果与
掩码
行的总和进行比较,看哪一行匹配

result = masks * n;
matches = sum(masks, 2) == result;
match_count = sum(matches);
对于每个匹配,我们从能量中减去β。对于每个不匹配项,我们添加
beta
,因此

possible_matches = 25; %// the number of neighborhood types
energy = -beta * match_count + beta * (possible_matches - match_count);
现在我们所要做的就是找出如何让所有3x3社区脱离我们的形象。幸运的是,MATLAB有这样的功能。更好的是,它只需要图像的有效邻域,所以如果已经填充了,就可以开始了

function G = gibbs(img, beta, classcount)

   masks = [
      0   0   0   0   1   0   0   0   0;
      0   0   0   0   0   1   0   0   0;
      0   0   0   1   0   0   0   0   0;
      0   0   0   0   0   0   0   1   0;
      0   1   0   0   0   0   0   0   0;
      1   0   0   0   0   0   0   0   0;
      0   0   0   0   0   0   0   0   1;
      0   0   0   0   0   0   1   0   0;
      0   0   1   0   0   0   0   0   0;
      1   1   0   0   0   0   0   0   0;
      1   0   0   1   0   0   0   0   0;
      0   0   0   1   0   0   1   0   0;
      0   0   0   0   0   0   1   1   0;
      0   0   0   0   0   0   0   1   1;
      0   0   0   0   0   1   0   0   1;
      0   0   1   0   0   1   0   0   0;
      0   1   1   0   0   0   0   0   0;
      0   0   0   1   0   0   0   1   0;
      0   0   0   0   0   1   0   1   0;
      0   1   0   1   0   0   0   0   0;
      0   1   0   0   0   1   0   0   0;
      1   1   0   1   0   0   0   0   0;
      0   0   0   1   0   0   1   1   0;
      0   0   0   0   0   1   0   1   1;
      0   1   1   0   0   1   0   0   0];

   [m,n] = size(img);
   possible_matches = size(masks, 1);
   Imlabel = padarray(img, [1 1], 'replicate', 'both');

   col_label = im2col(Imlabel, [3 3], 'sliding');
   target = repmat(sum(masks, 2), [1, m*n]);

   for ii = 1:classcount
      found = masks*(col_label == ii);
      match_count = sum(found == target, 1);
      energy = -beta * match_count + beta*(possible_matches - match_count);
      G(:,:,ii) = reshape(energy, m, n);
   end

end

查表 如果你看矩阵乘法解,它是将每个像素的邻域乘以25个遮罩。对于1000 x 1000图像,这是
1000 x 1000 x 25 x 9=225M
乘法。但是只有
512
(2^9)个可能的邻居配置。因此,如果我们计算出这512个配置是什么,将它们乘以掩码,并将匹配项相加,我们就得到了一个512个元素的查找表,我们所要做的就是计算图像中每个邻域的索引。下面介绍如何使用上面的
掩码创建查找表:

possible_neighborhoods = de2bi(0:511, 9).';
found = masks * possible_neighborhoods;
target = repmat(sum(masks, 2), [1, size(found, 2)]);
LUT = sum(found == target, 1);
这与我们以前在每个循环中所做的差不多,但我们在所有可能的邻域中都这样做,这相当于数字
0:511
的所有位模式

现在,我们希望查找表中有一个十进制索引,而不是用掩码乘以每个像素的二进制向量。为此,我们可以将
conv2
与有效执行二进制到十进制转换的内核一起使用:

k = [1   8   64;
     2  16  128;
     4  32  256];

or

k = [2^0  2^3  2^6
     2^1  2^4  2^7
     2^2  2^5  2^8];
这将为每个像素提供
0:511
的值,因此我们添加一个值以获得
1:512
,并将其用作查找表的索引。以下是完整的代码:

function G = gibbs2(img, beta, classcount)

   masks = [
      0   0   0   0   1   0   0   0   0;
      0   0   0   0   0   1   0   0   0;
      0   0   0   1   0   0   0   0   0;
      0   0   0   0   0   0   0   1   0;
      0   1   0   0   0   0   0   0   0;
      1   0   0   0   0   0   0   0   0;
      0   0   0   0   0   0   0   0   1;
      0   0   0   0   0   0   1   0   0;
      0   0   1   0   0   0   0   0   0;
      1   1   0   0   0   0   0   0   0;
      1   0   0   1   0   0   0   0   0;
      0   0   0   1   0   0   1   0   0;
      0   0   0   0   0   0   1   1   0;
      0   0   0   0   0   0   0   1   1;
      0   0   0   0   0   1   0   0   1;
      0   0   1   0   0   1   0   0   0;
      0   1   1   0   0   0   0   0   0;
      0   0   0   1   0   0   0   1   0;
      0   0   0   0   0   1   0   1   0;
      0   1   0   1   0   0   0   0   0;
      0   1   0   0   0   1   0   0   0;
      1   1   0   1   0   0   0   0   0;
      0   0   0   1   0   0   1   1   0;
      0   0   0   0   0   1   0   1   1;
      0   1   1   0   0   1   0   0   0];

   [m,n] = size(img);
   possible_matches = size(masks, 1);
   possible_neighborhoods = de2bi(0:511, 9).';   %'
   found = masks * possible_neighborhoods;
   target = repmat(sum(masks, 2), [1, size(found, 2)]);
   LUT = sum(found == target, 1);
   
   k = [1   8   64;
        2  16  128;
        4  32  256];
        
   Imlabel = padarray(img, [1 1], 'replicate', 'both');

   for ii = 1:classcount
      filterImage = conv2(double(Imlabel == ii), k, 'valid');
      matchImg = LUT(filterImage + 1);
      G(:,:,ii) = -beta * matchImg + beta * (possible_matches - matchImg);
   end
   
end

因为我们对1000x1000图像进行的乘法要少得多,所以这种方法比我机器上使用倍频程的矩阵乘法方法快7倍左右。

为什么不创建遮罩,然后再进行乘法?@AnderBiguri:你认为会更快吗?是的。MATtrix LABoratory被设计为使用Matrix最快的实验室。您能实现它吗?我想和原始代码在计算时间方面进行比较?谢谢你,哈哈哈。没有。你看过你的代码有多长吗?真是太神奇了。我正在测量性能。我以后会告诉你的。我在matlab的第二个代码中发现了一个小错误。行Imlabel==ii(在conv2(Imlabel==ii,…)中)需要转换为double as double(Imlabel==ii)。是的,显然MATLAB希望conv2
的参数为single或double。我来换一下。谢谢你的烧杯。我花时间去理解和衡量你的方式。正如我在MATLAB中的检查,与我的方法相比,对于4类大小为500x500的矩阵,第一种方法的速度提高了2倍,第二种方法的速度提高了13倍。这真是个好办法。我明白第一种方法。然而,我仍然不明白第二条路。为什么有2^9个可能的邻居,而不是2^10?4个邻域(是2^2吗?)有多少个可能的邻居配置