Визуализация цветов шума
Вступление
Шум может быть интересной темой, поскольку он, по-видимому, заложен в основу многих систем, таких как MRI, RADAR, SONAR, и GPS. Обычно это помеха, которая блокирует желаемый сигнал, но сегодня мы воспользуемся другим подходом и узнаем о цветах шума. Затем мы узнаем, как генерировать и отображать эти цвета шума в виде изображений, используя цветовое пространство HSV. Далее мы увидим, что действительно можем визуализировать цвет любого сигнала.
Код для этого руководства находится здесь.
Что такое цвета шума?
Цвет конкретного источника шума относится к форме его спектральной плотности мощности или PSD [1]. PSD количественно определяет уровни мощности сигнала на каждой частоте; некоторые примеры показаны ниже:
Различные цвета шума обычно относятся к звуку, который они издают. Источники шума, такие как розовый шум или коричневый шум, как правило, обладают приятным эффектом маскировки других звуков. Их мощность уменьшается с увеличением частоты, что означает, что присутствует меньше высокочастотных компонентов, что обеспечивает плавный слышимый тон. Мощность синего шума увеличивается с увеличением частоты, что приводит к резкому тону, полному высокочастотных компонентов [1, 2].
Как мы можем визуализировать эти цвета?
Цвета шума можно визуализировать, применив их спектры мощности к цветовому спектру.
Основная процедура заключается в масштабировании спектральной плотности мощности до 0-1 и выборке из неё, где 0 начинается с красного около 700 нм, а 1 заканчивается фиолетовым около 400 нм. Следуя этой процедуре, мы получим сочетание цветов в количествах, соответствующих спектральной плотности мощности.
Цвета шума
Мы узнаем, как визуализировать цвета шума в 2D-перспективе. Сначала мы генерируем одноканальное изображение белого гауссова шума:
white_noise = np.random.normal(loc=0, scale=1, size=(N, N))
На изображениях цветные шумовые пиксели имеют корреляции друг с другом. Мы можем добавить эти корреляции с помощью операции сглаживания, при которой ядро свёртывается с белым шумом. Операция сглаживания уменьшает высокие частоты и добавляет пространственные зависимости. Мы будем стремиться генерировать 3 различных цвета шума: красный, зеленый и фиолетовый. Чтобы получить эти цвета шума, нам нужно будет спроектировать ядра, которые дадут нам соответствующие спектральные плотности мощности для каждого цвета. (В основном это было методом проб и ошибок).
- Красный — Используйте большое усредняющее ядро
- Зеленый — Используйте ядро из нулей с верхним левым углом, установленным на высокие значения.
- Фиолетовый — Используйте 2D-функцию Shah [5]
# красный шум
red_kernel = np.ones((N2, N2), dtype=np.float64)
red_kernel /= red_kernel.sum()
red_noise = cv2.filter2D(white_noise, ddepth=-1, kernel=red_kernel)
# зелёный шум
green_kernel = np.zeros((5,5), dtype=np.float64)
green_kernel[0:2, 0:2] = 9
green_kernel /= green_kernel.sum()
green_noise = cv2.filter2D(white_noise, ddepth=-1, kernel=green_kernel)
# фиолетовый шум
purple_kernel = np.zeros((N2, N2), dtype=np.float64)
purple_kernel[0::3, 0::3] = 1
purple_kernel /= purple_kernel.sum()
purple_noise = cv2.filter2D(white_noise, ddepth=-1, kernel=purple_kernel)
Интересно, что необработанное изображение каждого цвета шума отличается друг от друга. Теперь мы проверим их автокорреляции, чтобы получить больше информации об их различиях. В общем, автокорреляция изображения показывает, насколько похож (коррелирован) каждый пиксель друг на друга.
# compute autocorrelations
red_ac = cv2.filter2D(red_noise, ddepth=-1, kernel=red_noise)
green_ac = cv2.filter2D(green_noise, ddepth=-1, kernel=green_noise)
purple_ac = cv2.filter2D(purple_noise, ddepth=-1, kernel=purple_noise)
Из автокорреляций мы можем видеть, что пиксели красного шума имеют пространственные корреляции с соседними пикселями, которые ослабевают с расстоянием. Зелёный шум имеет очень сильные локальные корреляции только с окружающими пикселями и очень слабые корреляции везде ещё. Автокорреляция фиолетового шума демонстрирует пространственный паттерн, в котором сильные корреляции возникают в каждом третьем пикселе, что, непосредственно, соответствует используемому нами ядру. Давайте посмотрим поближе:
Теперь давайте вычислим спектральные плотности мощности, используя двумерное преобразование Фурье автокорреляций:
# compute PSDs
red_psd = np.abs(np.fft.fftshift(np.fft.fft2(red_ac)))
green_psd = np.abs(np.fft.fftshift(np.fft.fft2(green_ac)))
purple_psd = np.abs(np.fft.fftshift(np.fft.fft2(purple_ac)))
Их величины отображаются с логарифмически масштабированной интенсивностью и пространственными частотами вдоль осей.
Поскольку мы использовали симметричные ядра для генерации цветов шума, их PSD симметричны. Мы возьмём среднее значение по столбцам и построим графики PSD в 1D с логарифмической шкалой.
Обратите внимание на взаимосвязь между пространственной областью (автокорреляция) и частотным пространством (спектральная плотность мощности).
- Красный — сильно распределённая интенсивность в пространственной области, сильно сконцентрирована в частотном пространстве
- Зелёный — концентрированная интенсивность в пространственной области, сильно распределена в частотном пространстве
- Фиолетовый — Близко расположено в пространственной области.
Выборка по спектральным плотностям
Поскольку PSD симметричны, мы будем использовать односторонний PSD, масштабируем их с 0-1 и нормализуем так, чтобы их сумма равнялась 1. Это будут наши плотности выборки:
# N2 is half the number of rows/cols
# red noise probability
half_red_probs = red_psd.mean(axis=0)[N2:]
half_red_probs /= half_red_probs.sum()
# green noise probability
half_green_probs = green_psd.mean(axis=0)[N2:]
half_green_probs /= half_green_probs.sum()
# purple noise probability
half_purple_probs = purple_psd.mean(axis=0)[N2:]
half_purple_probs /= half_purple_probs.sum()
Теперь мы можем выбрать массивы (NxN) из этих плотностей, используя numpy:
# sample images from single sided distributions
sampled_red_image = np.random.choice(a=np.linspace(0, 1, N2), size=(N, N), p=half_red_probs)
sampled_green_image = np.random.choice(a=np.linspace(0, 1, N2), size=(N, N), p=half_green_probs)
sampled_purple_image = np.random.choice(a=np.linspace(0, 1, N2), size=(N, N), p=half_purple_probs)
Теперь мы можем начать видеть, откуда берутся цвета. Красный шум сильно сконцентрирован вокруг постоянного тока (частота 0). Зеленый шум имеет отклонение от 0 до 300, которое охватывает красный, жёлтый, зелёный, голубой и синий цвета. Фиолетовый шум представляет собой смесь 2 режимов при 0 и 240, которые соответствуют красному и голубому / синему. Каждая из этих плотностей представляет собой смесь цветов.
На самом деле мы можем сделать это с любым сигналом. Всё, что нам нужно сделать, это вычислить его односторонний PSD и взять образец из него, чтобы получить цветовую смесь.
Цветовое пространство HSV
Чтобы отобразить эти отобранные изображения в виде цветов, нам нужно преобразовать их интенсивность в каждом пикселе в цвет. Мы сделаем это с помощью цветового пространства HSV, которое расшифровывается как:
- Оттенок — определяет цвет (диапазон от 0 до 360 градусов)
- Насыщенность — описывает количество серого в определённом цвете. Диапазон от: 0% — Серый, 100% — Чистый основной цвет
- Значение — описывает яркость/насыщенность цвета Диапазон от: 0% — Черный, 100% — самый яркий.
Мы установим насыщенность и значение равными 100% и будем использовать выбранные интенсивности для настройки оттенка. Затем мы можем преобразовать обратно в цветовое пространство RGB и отобразить изображения.
import colorsys
get_rgb = np.vectorize(lambda x: colorsys.hsv_to_rgb(x, 1, 1))
# get noise color images
red_noise_image = np.dstack(get_rgb(sampled_red_image))
green_noise_image = np.dstack(get_rgb(sampled_green_image))
purple_noise_image = np.dstack(get_rgb(sampled_purple_image))
В каждом изображении у нас есть только нужное количество каждого цветного пикселя, и все они конструктивно объединяются, образуя тот цвет, который мы видим.
ПРИМЕЧАНИЕ: Из-за выборки вы можете получить результаты не по цвету. Если это произойдёт, просто повторите выборку несколько раз, особенно это происходит с зелёным шумом.
Заключение
Мы увидели, как генерировать различные цвета шума, применяя операции с пространством изображения для введения пространственных корреляций и уменьшения различных частотных составляющих. Мы визуализировали их автокорреляции и спектры мощности, которые представляли взаимосвязь между пространственной областью (пространством изображений) и пространством Фурье. Затем мы смогли использовать односторонний PSD в качестве дистрибутива для выборки интенсивности. Далее мы преобразовали отобранные интенсивности в цвета HSV и отобразили их в виде изображений RGB.
И, наконец, мы узнали, что можем визуализировать цвет любого сигнала. Всё, что нам нужно сделать, это вычислить его одностороннюю спектральную плотность мощности, масштабировать её от 0 до 1, взять из неё значения интенсивности и преобразовать интенсивности в цветовое пространство HSV.
Ссылки на используемую литературу
[1] Wikimedia Foundation. (2023, February 19). Colors of noise. Wikipedia. Retrieved March 13, 2023, from https://en.wikipedia.org/wiki/Colors_of_noise
[2] King, H. (2023, March 10). The colors of noise. Molekule Blog. Retrieved March 13, 2023, from https://molekule.com/blog/the-colors-of-noise/
[3] Wikimedia Foundation. (2023, February 22). Spectral density. Wikipedia. Retrieved March 13, 2023, from https://en.wikipedia.org/wiki/Spectral_density
[4] Bear, J. H. (2020, July 29). Understanding the HSV color model. Lifewire. Retrieved March 13, 2023, from https://www.lifewire.com/what-is-hsv-in-design-1078068
[5] Stanford Engineering Everywhere | Home. (n.d.). Retrieved March 13, 2023, from https://see.stanford.edu/materials/lsoftaee261/chap8.pdf