Я задал этот вопрос в течение некоторого времени, надеясь, что кто-то напишет ответ сглаживания, так как я обдумываю ту же проблему.
Вот моя собственная попытка; Я не тестировал это, но я думаю, что вы можете делать повторную дилатацию и эрозию с любым элементом структурирования, только дважды обращаясь к каждому пикселю:
Предположения. Предположим, что структурирующий элемент/ядро является прямоугольником KxL, а изображение является Прямоугольник NxM. Предположим, что K и L нечетны.
Основной подход, который вы наметили, имеет четыре для петель и принимает O(K*L*N*M)
времени для завершения.
Часто вы хотите размножаться повторно одним и тем же ядром, поэтому время снова умножается на необходимое количество разведений.
У меня есть три основных идей для ускорения дилатации:
дилатации на ядре K равно дилатацию по KX1 ядра с последующим растяжением на ядре 1XL.Вы можете сделать оба этих растяжений только три для петель, в O (K N M) и O (L N M)
Однако вы можете сделать дилатации с KX1 ядра намного быстрее: Вы требуется только один раз получить доступ к каждому пикселю. Для этого вам нужна конкретная структура данных, поясняемая ниже. Это позволяет делать одиночную дилатацию в O (N * M), независимо от размера ядра
Повторная дилатация ядра Kx1 равна единице дилатации большим ядром. Если вы расширяете P раз ядром Kx1, это равно одной дилатации с ядром ((K-1)*P + 1) x 1
. Таким образом, вы можете выполнять повторную дилатацию с любым размером ядра за один проход в O (N * M).
Теперь для детального описания шага 2.
Вам нужна очередь со следующими свойствами:
- толчок элемент к задней части очереди в постоянная время.
- поп элемент от передней части очереди в постоянное время.
- запрашивает текущий самый маленький или самый большой элемент в очереди в постоянное время.
Как построить такую очередь описана в этом ответе stackoverflow: Implement a queue in which push_rear(), pop_front() and get_min() are all constant time operations. К сожалению, не много псевдокодов, но основная идея кажется звуковой.
Использование такой очереди, вы можете вычислить KX1 дилатацию за один проход:
Assert(StructuringElement.dy()==1);
int kernel_half = (StructuringElement.dx()-1) /2;
for(y < dy) { // y loop
for(x <= kernel_half) { // initialize the queue
queue.Push(src(x, y));
}
for(x < dx) { // x loop
// get the current maximum of all values in the queue
dst(x, y) = queue.GetMaximum();
// remove the first pixel from the queue
if (x > kernel_half)
queue.Pop();
// add the next pixel to the queue
if (x < dx - kernel_half)
queue.Push(src(x + kernel_half, y));
}
}
Это не полное решение, а всего лишь одна идея: я считаю, что операция разложима, т. Е. Вы можете получить расширение 3x3, выполнив расширение 3x1 и расширение 1x3 в строке, что намного быстрее. Дилатация 1x9 может быть разложена на две разложения 1x3. (Я знаю, что это верно для размытия Gaussian, но я не уверен, относится ли это к эрозии/расширению.) – HugoRune