我想加快我的代码速度。目前,我用if语句来做。但是,如果我们使用convolution way,它可以制作更快的代码。但是,它仅适用于简单情况(作为成对邻域)。让我们来定义我的问题。
我有一个矩阵I=[1 1 1;2 2 2;2 2 1]
,它有两个标签{1,2}
。我添加了填充作为其右侧。对于I
中的每个像素,我们可以定义邻域的成对或三倍。我们将根据规则检查"如果这些邻域值与像素具有相同的类别,则设置成本值等于-beta
,否则将成本设置为beta
&#34;。< / p>
例如,让我们考虑上图中的黄色像素。它的标签是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');
答案 0 :(得分:1)
以下是我对此的尝试。我无法确定是否有一个对你更快,因为我使用Octave而不是MATLAB,时间可能狂野不同。例如,for
循环仍然在Octave中永远存在。你必须测试它们,看看它们是如何比较的。
作为@AnderBiguri notes in the comments,一种方法是使用矩阵乘法。如果您选择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];
现在,当您将masks
乘以邻域时,您可以立即获得所有结果。然后将结果与masks
行的总和进行比较,以查看哪些匹配。
result = masks * n;
matches = sum(masks, 2) == result;
match_count = sum(matches);
对于每场比赛,我们从能量中减去beta
。对于每个不匹配,我们添加beta
,所以
possible_matches = 25; %// the number of neighborhood types
energy = -beta * match_count + beta * (possible_matches - match_count);
现在我们所要做的就是弄清楚如何从我们的图像中获取所有3x3邻域。幸运的是,MATLAB具有im2col功能,可以做到这一点。更好的是,它只需要图像的有效邻域,所以如果它已经填充,你就可以开始了。
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
如果你看一下Matrix Multiplication解决方案,它会将每个像素的邻域乘以25个掩码。对于1000 x 1000图像,即1000 x 1000 x 25 x 9 = 225M
次乘法。但是只有512
(2 ^ 9)个可能的邻居配置。因此,如果我们弄清楚这512个配置是什么,将它们乘以掩码,并总结匹配,我们有一个512个元素的查找表,我们要为图像中的每个邻域做的所有事情都是计算它的指数。以下是使用上面的masks
创建查找表的方法:
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图像的乘法运算少得多,因此这种方法比使用Octave的机器上的矩阵乘法方法快7倍。