адаптивный эллиптический элемент структурирования в MATLAB

Я пытаюсь создать адаптивный эллиптический структурирующий элемент для изображения, чтобы расширить или размыть его. Я пишу этот код, но, к сожалению, все элементы структурирования ones(2*M+1).

I = input('Enter the input image: ');
M = input('Enter the maximum allowed semi-major axes length: ');

% determining ellipse parameteres from eigen value decomposition of LST

row = size(I,1);
col = size(I,2);
SE = cell(row,col);
padI = padarray(I,[M M],'replicate','both');
padrow = size(padI,1);
padcol = size(padI,2);

for m = M+1:padrow-M
   for n = M+1:padcol-M

      a = (l2(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
      b = (l1(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;

      if e1(m-M,n-M,1)==0
         phi = pi/2;
      else
         phi = atan(e1(m-M,n-M,2)/e1(m-M,n-M,1));
      end

      % defining structuring element for each pixel of image

      x0 = m;  
      y0 = n;
      se = zeros(2*M+1);
      row_se = 0;
      for i = x0-M:x0+M
         row_se = row_se+1;
         col_se = 0;
         for j = y0-M:y0+M
            col_se = col_se+1;
            x = j-y0;
            y = x0-i;
            if ((x*cos(phi)+y*sin(phi))^2)/a^2+((x*sin(phi)-y*cos(phi))^2)/b^2 <= 1
               se(row_se,col_se) = 1;
            end
         end
      end

      SE{m-M,n-M} = se;
   end
end

a, b и phi — длина большой и малой полуосей, а фи — угол между a и осью x.

Я использовал 2 функции MATLAB для вычисления тензора локальной структуры изображения, а затем его собственных значений и собственных векторов для каждого пикселя. Это матрицы l1, l2, e1 и e2.


person bahar    schedule 24.04.2018    source источник
comment
Это не полный код. Где определены l1, l2 и e1? -- Не используйте atan, используйте atan2. -- Почему вы делаете for i = x0-M:x0+M, а затем y = x0-i вместо for y = -M:M?   -  person Cris Luengo    schedule 25.04.2018
comment
Ошибка в вашем коде, вероятно (без возможности видеть l1 и l2 и т. д.), что a и b больше, чем M.   -  person Cris Luengo    schedule 25.04.2018
comment
В дополнение к комментарию @CrisLuengo, деление eps, как правило, не очень хорошая идея. Что вы пытаетесь сделать с eps?   -  person Yvon    schedule 25.04.2018
comment
@CrisLuengo: Спасибо за помощь. Я использовал 2 функции Matlab для вычисления тензора локальной структуры изображения, а затем его собственных значений и собственных векторов, то есть l1, l2, e1 и e2 для каждого пикселя.   -  person bahar    schedule 25.04.2018
comment
@CrisLuengo: я использую i = x0-M:x0+M, потому что хочу связать систему координат, т. е. x и y, со строками и столбцами изображения в определенной окрестности, т. е. [M M] каждого пикселя, т. е. x0 и y0.   -  person bahar    schedule 25.04.2018
comment
@Ивон: Спасибо. деление на ноль и идеально сглаженные области обрабатываются путем добавления небольшого положительного числа, т. е. eps, к собственным значениям. это выражено в моем справочном документе.   -  person bahar    schedule 25.04.2018
comment
@CrisLuengo: Хорошо. ты прав. Я могу использовать y = -M:M вместо i = x0-M:x0+M и y = x0-i. Спасибо.   -  person bahar    schedule 25.04.2018
comment
Ok. Тем не менее eps/l1(m-M,n-M) выглядит очень неразумным для меня. Я думаю, что у @CrisLuengo есть ответ на этот вопрос.   -  person Yvon    schedule 25.04.2018
comment
Не могли бы вы предоставить способ получить l1 l2 e1 и e2, чтобы мы могли запустить ваш код? Если фактический расчет слишком длинный, не могли бы вы составить несколько фиктивных значений, которые входят в правильный диапазон? Я спрашиваю об этом, потому что у нас есть требование минимального воспроизводимого примера.   -  person Yvon    schedule 25.04.2018


Ответы (1)


Это часть вашего кода, которую я не понял:

a = (l2(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
b = (l1(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;

Я упростил выражение для b до (просто удалив индексацию):

b = (l1+eps/l1+l2+2*eps)*M;

Для l1 и l2 в пределах нормы получаем:

b =(approx)= (l1+0/l1+l2+2*0)*M = (l1+l2)*M;

Таким образом, b может легко быть больше, чем M, что я не думаю, что вы намерены. eps в этом случае также не защищает от деления на ноль, что обычно является целью добавления eps: если l1 равно нулю, eps/l1 равно Inf.

Глядя на это выражение, мне кажется, что вы имели в виду это вместо этого:

b = (l1+eps)/(l1+l2+2*eps)*M;

Здесь вы добавляете eps к каждому из собственных значений, делая их гарантированно ненулевыми (структурный тензор симметричный, положительно полуопределенный). Затем вы делите l1 на сумму собственных значений и умножаете на M, что приводит к значению от 0 до M для каждой из осей.

Таким образом, это, кажется, случай неуместной скобки.

Просто для записи, это то, что вам нужно в вашем коде:

a = (l2(m-M,n-M)+eps ) / ( l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
b = (l1(m-M,n-M)+eps ) / ( l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
                     ^   ^
                added parentheses

Обратите внимание, что вы можете упростить свой код, определив вне циклов:

[se_x,se_y] = meshgrid(-M:M,-M:M);

Два внутренних цикла по i и j для построения se могут быть записаны просто как:

se = ((se_x.*cos(phi)+se_y.*sin(phi)).^2)./a.^2 + ...
     ((se_x.*sin(phi)-se_y.*cos(phi)).^2)./b.^2 <= 1;

(Обратите внимание на операторы .* и .^, они выполняют поэлементное умножение и степень.)

Еще одно небольшое улучшение связано с осознанием того, что phi сначала вычисляется из e1(m,n,1) и e1(m,n,2), а затем используется в вызовах cos и sin. Если предположить, что собственный вектор правильно нормализован, то

cos(phi) == e1(m,n,1)
sin(phi) == e1(m,n,2)

Но вы всегда можете убедиться, что они нормализованы:

cos_phi = e1(m-M,n-M,1);
sin_phi = e1(m-M,n-M,2);
len = hypot(cos_phi,sin_phi);
cos_phi = cos_phi / len;
sin_phi = sin_phi / len;
se = ((se_x.*cos_phi+se_y.*sin_phi).^2)./a.^2 + ...
     ((se_x.*sin_phi-se_y.*cos_phi).^2)./b.^2 <= 1;

Учитывая, что тригонометрические операции довольно дороги, это должно немного ускорить ваш код.

person Cris Luengo    schedule 25.04.2018
comment
Кажется, вы ответили на мой вопрос. OP не хотел делить eps на число, что, я думаю, мало помогает в расчетах. - person Yvon; 25.04.2018
comment
Да, кстати, было бы лучше, если бы вы использовали l1 + eps(l1) и так далее. eps без входного аргумента по умолчанию равно eps(1), что является наименьшим числом, которое нужно добавить к 1, чтобы получить сумму, отличную от 1. Теперь рассмотрим случай, когда abs(l1) < eps(1). Например. l1=1e-30 и l2=2e-30 и l1/l2 не являются операцией деления на ноль. - person Yvon; 25.04.2018
comment
@Yvon Что делает eps(0)? Суть не в том, чтобы создать что-то немного большее, чем l1, а в том, чтобы убедиться, что l1 не равно 0. - person Cris Luengo; 25.04.2018
comment
eps(0) = 4.9407e-324 и 1/eps(0) = Inf Также, если l1 = 1e-30; l2 = 2e-30;, то l1/l2 = 0.5000 и l1/(l2+eps) = 4.5036e-15 - person Yvon; 26.04.2018
comment
@Yvon: собственные значения тензора структуры имеют тот же порядок величины, что и квадрат градиента изображения. Таким образом, если l1 = 1e-30, его можно считать 0 (все, что меньше 1e-6, для меня в этих случаях является ошибкой округления). На самом деле я бы реализовал это просто как l1/(l1+l2+1e-6) или что-то в этом роде. Другой альтернативой является точечный минимум l1=min(l1,1e-6). - person Cris Luengo; 26.04.2018
comment
влияет ли это на результат se - person Yvon; 26.04.2018
comment
@Ивон: я бы так не подумал. Идея состоит в том, чтобы иметь круглую SE (ядро фильтра), когда два собственных значения подобны (что означает, что локально на изображении нет предпочтительного направления), и делать его тем более вытянутым, чем больше разница между двумя собственными значениями (т.е. предпочтительная ориентация). Когда оба собственных значения очень малы, изображение локально однородно, и фильтрация будет малоэффективной независимо от формы фильтра. - person Cris Luengo; 26.04.2018
comment
@Yvon: Если вам интересно, это документ, в котором описывается метод, который OP пытается реализовать. Здесь есть файл в формате PDF. В этой статье говорится, что деление на ноль [в] идеально гладких областях обрабатывается путем добавления небольшого положительного числа к собственным значениям (достаточно малому, чтобы им можно было пренебречь для любых других целей, например, для машинного эпсилон). - person Cris Luengo; 26.04.2018
comment
хм, если они не заботятся об операциях с очень маленькими значениями, то, вероятно, это нормально. Хорошо исключить эту вещь из проблемы ОП. - person Yvon; 26.04.2018
comment
@Cris Luengo: Спасибо за вашу огромную помощь. Я использовал это выражение: a = (l2(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;, потому что я вынужден дополнять свое изображение соседними пикселями: padI = padarray(I,[M M],'replicate','both');, но я вычислил собственные значения и собственные векторы раньше и сохранил их в матрице с размером исходного изображения. Я имею в виду, что l1,l2,e1, e2(1,1) соответствуют пикселю m = M+1, n = M+1 в дополненном изображении. - person bahar; 26.04.2018
comment
@bahar: я понимаю индексацию, я удалил это из ответа, чтобы упростить задачу. Это помогло мне понять уравнение, которое вы пытались реализовать. Добавление скобок решает вашу проблему? Если это так, пожалуйста, примите ответ, чтобы было ясно, что ваша проблема решена. Я вижу, что у вас довольно много вопросов по SO, и вы не приняли ни одного ответа. Пожалуйста, просмотрите их и примите ответы, если они были вам полезны. См. здесь: meta.stackexchange.com/a/5235/376604 - person Cris Luengo; 26.04.2018
comment
@CrisLuengo: извините. Я не знал, чтобы принять ответы. Спасибо большое. Я мог бы создать элементы структурирования с вашей помощью. К сожалению, я не могу сделать адаптивное расширение с этими SE, используя matlab 'imdilate', и получить выходное изображение. Есть идеи? - person bahar; 27.04.2018
comment
@bahar: Это правда, стандартные алгоритмы расширения предполагают фиксированную SE. Вам придется реализовать собственное расширение, чтобы использовать адаптивную SE. Это не так сложно, как кажется. Для каждого выходного пикселя поместите свой конкретный SE в его центр и прочитайте все входные пиксели, которые он накладывает. Затем возьмите максимальное значение этих пикселей и используйте его в качестве выходного значения. Вам нужно отдельное выходное изображение, вы не можете писать на входном изображении, пока делаете это! Если у вас возникли проблемы с реализацией этого, я предлагаю вам задать новый вопрос. - person Cris Luengo; 27.04.2018
comment
@bahar: Рискуя побудить вас публиковать вопросы в качестве ответов (поле ответов предназначено для ответов на вопросы, а не для их задавания): ваша проблема находится в строке W = SE{i-M,j-M}.*padf(i-M:i+M,i-M:i+M);. Вы используете i для индексации в обоих направлениях! Кроме того, при умножении на SE ваш min всегда будет равен 0. Вам нужно использовать SE для индексации: W = padf(...); W = W(SE{...});. - person Cris Luengo; 28.04.2018