我有一个384*512*3
RGB
矩阵。只有512
个独特的颜色可以用不同的权重重复。从他们,我必须选择一半,另一半必须用第一个最接近的元素替换。
我想过循环遍历图像,并搜索当前颜色的最接近的颜色。找到后,我将其中一个替换为另一个。
但我有3个循环1:384
,1:512
,1:256
。前两个I循环通过RGB矩阵,第三个用于循环到包含最终颜色的矩阵。这需要一些时间来计算。
可以做些什么来加快速度?
循环看起来像这样:
dim=size(RGB);
for i=1:dim(1)
for j=1:dim(2)
aux=[RGB(i,j,1) RGB(i,j,2) RGB(i,j,3)];
minim=RGB_dist(uint8(V_colors_K(1,1:3)),aux);
index=1;
for k=1:K
%index=1;
if (minim>RGB_dist(uint8(V_colors_K(k,1:3)),aux))
minim=RGB_dist(uint8(V_colors_K(k,1:3)),aux);
index=k
end
RGB(i,j,1)=V_colors_K(index,1);
RGB(i,j,2)=V_colors_K(index,2);
RGB(i,j,3)=V_colors_K(index,3);
end
end
end
V_colors_K
代表被选为最终颜色的半色。
我可以考虑一些小的改进。如果颜色在good
一半中,则不需要最小距离。
这里的算法更精确:
定义1.函数D(c1,c2)是距离 在两个颜色矢量c1和c2之间,例如 欧氏距离。
定义2.函数P(c)是像素数 颜色c。 定义3.初始颜色集的基色cbase Q是满足等式的颜色
定义4.颜色c,V(c)的加权乘积, 定义为
其中wp是像素数的权重, 和wd是颜色距离的权重。
给定第一个颜色cbase,我们的方法计算 其他颜色和选择的加权产品 第一个K-1最大的产品。相应的 使用具有基色的K-1颜色 形成一个初始调色板。左N-K颜色与初始中最接近的颜色合并 用于生成最终调色板的调色板。
RGB_dist功能:
function[distance]=RGB_dist(x,y)
distance=sqrt(sum((double(x-y)).^2*[3;4;2],2));
end
我有一个适用于整个矩阵的函数,它计算所有对之间的距离。
function[D]=RGB_dist_full_2(x)
I = nchoosek(1:size(x,1),2);
D = squareform(RGB_dist(x(I(:,1),:), x(I(:,2),:)))
end
然后,我需要在每列上得到最小值。
答案 0 :(得分:1)
如果我正确阅读此内容,则您将RGB_dist()
成对操作应用于V_colors_k
中的每种颜色和RBG
中的每个像素。如果RGB_dist()
是线性函数,就像点积,那么您可以一次性将它应用于整个矩阵。例如,如果它是点积,那么您可以用:
DISTS = V_colors_K * RGB(i,j,:)';
k = find( DISTS == min(DISTS(:)) );
RGB(i,j,:) = V_colors_K(k,:);
不知道RBG_dist()
中的内容我无法给你一个更好的答案。我能给出的一般答案是:Matlab循环很慢,如果你想让它快速运行,你需要删除所有循环并只使用矩阵运算(快速闪烁)。用矩阵操作替换循环的过程称为矢量化代码,这可能很棘手。如果不知道你在RBG_dist()
内做了什么,就不可能为你提供完整的矢量化。
我在matlab中的常用工作流程是用循环的直观方式编写一些东西,就像你一样,然后一旦它给我正确的结果我回过头来弄清楚如何向量化它(即用矩阵运算替换所有循环)到快一点。矢量化是棘手的,它就像一个线性代数拼图,加速总是比我首先编写代码花费更长的时间。
更新:
我得到的最好的就是在你的基色上使用一个循环。你与RGB_dist函数非常接近,因为该行在整个矩阵中都能很好地工作:
[RGBwidth RGBHeight RGBdepth] = size(RGB);
minDists=inf( [RGBwidth RGBheight] );
bestKs=zeros( [RGBwidth RGBheight] );
for k=1:K
% make matrix out of the color k, the same shape as RGB
color_K_mat = premute(repmat(V_colors_K(k,:), [RGBwidth 1 RGBheight]), [3 1 2]);
% compute the distance from each pixel's color to color k
dists = sqrt(sum((RGB-color_K_mat).^2, 3));
% create a binary mask showing which pixels are closer to this color than to any previous one
mask = (dists < minDists);
% update your results matrices
bestKs = not(mask)*bestKs + mask*k
minDists = min(bestKs, dists);
end
% now bestKs(i,j) gives you the index k of the closest color for pixel (i,j)
% and minDists(i,j) gives you the distance to that color
理论上应该可以将这个循环矢量化,但这是一个更大的难题,我有自己的工作要做:P
答案 1 :(得分:0)
使用kmeans
:
img = im2double( img );
[IDX,C] = kmeans( reshape( img, [], 3 ), 256 ); %// cluster into 256 clusters
cimg = ind2rgb( reshape( IDX, size(img(:,:,1)) ), C );
答案 2 :(得分:0)
减少内循环操作: