2014-09-07 2 views
0

У меня есть матрица 384*512*3RGB. Есть только 512 уникальные цвета, которые повторяются с разными весами. Из них я должен выбрать половину, а вторую половину нужно заменить ближайшими элементами первого.Матричные вычисления

Я думал о том, чтобы прокручивать изображение и искать ближайший цвет для текущего. Найдя его, я заменяю его другим.

Но у меня есть 3 петли 1:384, 1:512, 1:256. С первыми двумя циклами я прохожу через матрицу 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 исходного цвета установлен В это цвет, который удовлетворяет уравнению

enter image description here

Определение 4. Взвешенный продукт цвета с V (с), определяется как

enter image description here

где в.ч. является вес от числа пикселей, и 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 

Тогда мне нужно будет получить минимум на каждом столбце.

+1

как вы выбираете половину цветов? Каков процесс? – shoham

+1

Можем ли мы увидеть, что вы делаете внутри цикла? В общем, вы никогда не должны зацикливаться на матрицах в matlab, почти все функции Matlab, работающие на одном числе, также будут работать на целой матрице одновременно, что будет в 1000 раз быстрее. –

+0

@shoham Я вычислил продукт между количеством пикселей, которые имеют этот цвет, и его расстоянием до базового цвета, который больше всего отображается на изображении. Один цвет - это базовый цвет, а остальные (половина-1) сортируются в порядке убывания на основе вычисленного продукта. –

ответ

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 заключается в том, чтобы написать что-то интуитивно понятным способом с помощью циклов, как и вы, а затем, как только он даст мне правильные результаты, я вернусь и выясню, как его векторизовать (т.е. заменить все циклы на операции с матрицей) чтобы сделать это быстро. Векторизация сложна, это похоже на головоломку с линейной алгеброй, и ускорение всегда заставляет меня ПУТЬ больше, чем писать код в первую очередь.

UPDATE:

Лучшее, что я получил использует одну петлю над вашими базисные цвета. Вы были очень близки с функцией 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

+0

Я обновил свой вопрос. Вы думали о лучшем решении? –

+1

Мне действительно не нравится делать всю работу для кого-то, но здесь вы идете. –

+1

@MikeOunsworth - Вы сделали больше, чем вам нужно, но я надеюсь, что OP может отнять что-то от этого и узнать что-то. – rayryeng

0

Использование kmeans:

img = im2double(img); 
[IDX,C] = kmeans(reshape(img, [], 3), 256); %// cluster into 256 clusters 
cimg = ind2rgb(reshape(IDX, size(img(:,:,1))), C); 
+0

Я уже использую k-средства для уменьшения изображения до разумного количества цветов. После этого мне нужно применить алгоритм, указанный мной в @shoham, в комментарии. –

0

для уменьшения операций внутреннего цикла:

  1. определяет вектор размера V_colors_K, со всеми значениями, назначенными в качестве Окса (назовет его v_aux).
  2. затем вычислить RGB_dist на v_aux vs V_colors_K.
  3. принять минимальный результат (он представляет минимальный цвет расстояния).
Смежные вопросы