У меня есть изображение, которое содержит много пикселей без данных. Изображение представляет собой массив 2d numpy, а значения без данных равны «Нет». Всякий раз, когда я пытаюсь применить к нему фильтры, кажется, что значения none учитываются в ядре и заставляют мои пиксели исчезать.
Например, у меня есть это изображение:
Я попытался применить к нему фильтр lee с помощью этой функции (взято из Speckle (Lee Filter) в Python):
from scipy.ndimage.filters import uniform_filter
from scipy.ndimage.measurements import variance
def lee_filter(img, size):
img_mean = uniform_filter(img, (size, size))
img_sqr_mean = uniform_filter(img**2, (size, size))
img_variance = img_sqr_mean - img_mean**2
overall_variance = variance(img)
img_weights = img_variance / (img_variance + overall_variance)
img_output = img_mean + img_weights * (img - img_mean)
return img_output
но результаты выглядят так:
с предупреждением:
UserWarning: Предупреждение: преобразование замаскированного элемента в nan. дв = np.float64 (self.norm.vmax) - np.float64 (self.norm.vmin)
Я также пытался использовать библиотеку findpeaks.
from findpeaks import findpeaks
import findpeaks
#lee enhanced filter
image_lee_enhanced = findpeaks.lee_enhanced_filter(img, win_size=3, cu=0.25)
но я получаю такое же пустое изображение. Когда я использовал медианный фильтр на том же изображении, с ndimage проблем не возникло.
Мой вопрос: как я могу запустить эти фильтры на изображении, не позволяя значениям None прерывать результаты?
изменить: я предпочитаю не устанавливать значение пикселей равным 0, потому что значение диапазона пикселей находится в диапазоне от -50 до 1 (это значения индекса). Кроме того, я боюсь, что если я изменю его на любое другое значение, например, 9999), это также повлияет на фильтр (я ошибаюсь?)
Редактировать 2: Я прочитал ответ Криса Луенго и попытался применить что-то подобное с медианным фильтром scipy.ndimage, поскольку понял, что результат также искажен.
Это исходное изображение:
Я попытался замаскировать значения Null:
idx = np.ma.masked_where(img,img!=None)[:,1]
median_filter_img = ndimage.median_filter(img[idx].reshape(491, 473), size=10)
zeros = np.zeros([img.shape[0],img.shape[1]])
zeros[idx] = median_filter_img
Результат выглядит так (цвет темнее, чтобы увидеть проблему по краям):
Как видно, кажется, что значения ребер зависят от значений None. Я сделал это также с img! = 0, но получил ту же проблему.
(просто добавить: значения пикселей находятся в диапазоне от 1 до -35)
@sai У меня не может быть нуля. моя цель - сгладить изображение и избавиться от шума (также в других изображениях, которые имеют больше шума, чем это)
1. заменить пустые значения на 0
, 2. создать маску пустых пикселей, 3. скопировать пустую область, 4. применить фильтр к изображению с 0, 5. снова установить маскированные значения на 0
@GrzegorzKrig Я боюсь, что изменение незначащих значений на 0 прервет результаты. Кроме того, я считаю, что сделал что-то похожее на вашу идею (появляется в сообщении)
Кажется, что простое решение - установить незначащие значения на ноль. Я не знаю, как бы вы обошли это, потому что большинство ядер обработки изображений требуют, чтобы вы применяли какое-то значение. a[numpy.argwhere(a==None)] = 0
Для фильтра не обязательно требовать некоторые значения. Это зависит от реализации
@byshiny, пожалуйста, смотрите исходный пост, я отредактировал свой пост относительно этого
Если вы хотите применить фильтр линейного сглаживания, вы можете использовать Normalized Convolution.
Основной рецепт таков:
По сути, мы нормализуем результат фильтра линейного сглаживания (свертки) по количеству пикселей с данными в окне фильтра.
В областях, где сглаженная маска равна 0 (далеко от данных), мы будем делить 0 на 0, поэтому там нужно соблюдать особую осторожность.
Обратите внимание, что нормализованная свертка может использоваться также для сомнительных данных, когда изображение маски получает значения в диапазоне от 0 до 1, что указывает на нашу уверенность в каждом пикселе. Например, пиксели, считающиеся зашумленными, могут иметь значение ближе к 0, чем другие пиксели.
Приведенный выше рецепт действителен только для линейных сглаживающих фильтров. Нормализованная свертка может быть выполнена с другими линейными фильтрами, например фильтрами производных, но в результате получается другой рецепт. См., например, здесь уравнение для нормализованной свертки для вычисления производной.
Для нелинейных фильтров необходимы другие подходы. Фильтры нелинейного сглаживания, например, часто не затрагивают края, поэтому они будут хорошо работать с изображениями с отсутствующими данными, если отсутствующие пиксели установлены на 0 или какое-либо значение далеко за пределами диапазона данных. Концепция сохранения изображения маски, которое указывает, какие пиксели имеют данные, а какие нет, всегда является хорошей идеей.
Спасибо за ваш ответ, я думаю, что пробовал что-то похожее на то, что вы предлагаете, но у меня все еще проблема с краями, вы можете прочитать отредактированную часть моего исходного сообщения, основанную на вашем ответе.
@Reut: медианный фильтр не является линейным фильтром, это не свертка. Средний фильтр является линейным. Фильтр сглаживания Гаусса является линейным. Какую проблему ты пытаешься решить? Убрать спекл-шум? Вы пробовали двусторонний фильтр с маленькой тональной сигмой и маленькой пространственной сигмой? Вы можете установить пиксели без выборки на 200 и просто запустить фильтр.
спасибо за ваш ответ, я попробую двусторонний фильтр. так как я новичок в этом хочу спросить - почему в данной ситуации работают только линейные фильтры?
@Reut: Потому что иначе математика не работает. Линейный сглаживающий фильтр представляет собой средневзвешенное значение. Нормализованная свертка изменила веса, используемые при усреднении, чтобы они были равны нулю для пикселей, не входящих в маску.
нельзя ли значения none заменить на
0
или это будет мешать работе фильтра? Кроме того, какова ваша основная цель здесь?