Просто добавь немного шума

Предыдущая статья о том, как профильтровать изображение и избавить его от цифрового импульсного шума, заставила подумать и над обратной задачей, особенно с учетом того, что приходилось постоянно напрягать Bagomot’а, который почти постоянно занят со своим проектом по доработке одного сайта, делать «шумные» картинки. Естественно, нужно было некоторое количество зашумленных изображений, которые делал мой товарищ, поскольку я (к своему стыду) вообще не дружу с графическими редакторами и вообще никак не умею с ними работать, и поэтому пришлось помучаться над тем, как добавить простейшие импульсные помехи, не прибегая при этом к помощи графических редакторов.

Вообще, для того, чтобы создать простейший вариант шумовых помех, какие-то специфические знания вообще не требуются — достаточно просто вспомнить про такую замечательную вещь, как генератор псевдослучайных чисел, который у нас любовно называют полным рандомом.

Добавление некоторого количества шума, которое удобно указывать в процентах (в том числе и в дробных процентах!), уже несколько более нетривиальная задача, но тем не менее она решается довольно просто: определяем размеры изображения (умножаем длину изображения на ширину изображения — и получаем общее количество точек изображения, если считать что размер одной точки равен 1), после чего определяем количество точек шума и в случайном порядке размещаем эти точки, которые можно раскрашивать либо строго определенным цветом, либо вообще случайным RGB-цветом, по всей площади исходного изображения.

Чтобы вычислить количество точек шума, необходимо просто умножить площадь исходного изображения, взятую в пикселях, на процент шума, поделенный на 100.0f (объясняю, почему так: делим процент шума на 100 процентов для перевода процентного содержания в дольную единицу, т.е. в обыкновенную десятичную дробь).

Проще всего сделать заполнение шумом определенного цвета, которое легко запрограммировать, например, вот так:

auto applyNoise(SuperImage source, float percentOfNoise, Color4f noiseColor)
{
	import std.random : Random, uniform, unpredictableSeed;

	auto noisedImage = source.dup;
	auto numberOfNoisePoints = cast(size_t) (noisedImage.width * noisedImage.height * (percentOfNoise / 100.0f));
	auto rng = Random(unpredictableSeed);

	for (size_t i = 0; i < numberOfNoisePoints; i++)
	{
		auto X = cast(int) uniform(0, noisedImage.width, rng);
		auto Y = cast(int) uniform(0, noisedImage.height, rng);
		noisedImage[X, Y] = noiseColor;
	}

return noisedImage;
}

Для испытания этой простейшей процедуры, ее необходимо применить к уже загруженому изображению:

void main()
{
	auto lenna = load("Lenna.png");
	lenna
           .applyNoise(19.5, Color4f(1.0f, 1.0f, 0.0f))
            .savePNG("noisedColorTest.png");
}

Как вы понимаете, в цифровой обработке изображений есть уже некоторые сложившиеся стандарты и традиции. Одним из таких неписанных стандартов является использование стандартного изображения для тестирования разного рода алгоритмов обработки, а самим стандартным изображением в данном случае служит изображение одной шведской модели, которое принято (по имени модели) именовать Леной.

В данном случае, я взял стандартное изображение из Википедии и наложил на него шум из желтых точек в количестве 19.5 % от всего объема изображения, что выглядит примерно так:

А теперь, исходя из предыдущих наработок нетрудно сделать и более хитроумный шум, который создает помеху цвет которой будет с каждым разом меняться по совершенно случайному закону:

auto applyNoise(SuperImage source, float percentOfNoise)
{
	import std.random : Random, uniform, unpredictableSeed;

	auto noisedImage = source.dup;
	auto numberOfNoisePoints = cast(size_t) (noisedImage.width * noisedImage.height * (percentOfNoise / 100.0f));
	auto rng = Random(unpredictableSeed);

	for (size_t i = 0; i < numberOfNoisePoints; i++)
	{
		auto X = cast(int) uniform(0, noisedImage.width, rng);
		auto Y = cast(int) uniform(0, noisedImage.height, rng);

		auto R = uniform(0.0f, 1.0f, rng);
		auto G = uniform(0.0f, 1.0f, rng);
		auto B = uniform(0.0f, 1.0f, rng);

		noisedImage[X, Y] = Color4f(R, G, B);
	}

	return noisedImage;
}

Применять это нужно также как и в предыдущем случае, но теперь параметр цвета уже не требуется и обе процедуры успешно могут существовать внутри одного и того же модуля (у меня так и сделано, не сомневайтесь), а компилятор автоматически определяет какую из них вызвать, что по сути, является перегрузкой функции.

А вот так это выглядит, если необходимо получить 1.5 % шума:

В общем-то, наложение шума — не такая уж проблема, особенно, если вспомнить кое-что из математики, которая и является источником методов обработки, а также и основной идеологией работы с изображениями ;). Кроме всего прочего, описанный вариант шума является довольно простой линейной аддитивной моделью, что собственно немного смущает: все таки это слишком простая модель, и довольно таки грубая модель цифрового шума, которая еще может быть усовершенствована (хотелось показать, что-то более интересное и красивое — но даже такие вещи, как простые линейные модели тоже нужны … хотя бы для разминки).

 

Добавить комментарий