Не думайте, что все это время, пока не появлялось новых записей, наш блог простаивал — на самом деле, у нас происходила целая куча событий, которые, однако, по большей части далеко не радуют…
Сначала, я хотел выложить перевод жутко интересной статьи, но потом выяснилось, что меня опередили, а в этот момент была готова только часть — и это меня очень расстроило, но потом я подумал, что нет смысла огорчаться — переводами сейчас занимаются многие, но вот чтобы написать нечто уникальное по D и к тому же на русском языке — вот тут нужно гораздо больше усилий и времени, и поэтому с приподнятым настроением я сел писать эту статью…
В одном из проектов, мне потребовалось сделать следующую вещь: взять некий байт из файла и проинтерпретировав его как число в интервале от 0 до 255, отобразить его как цвет пикселя в палитре 256 цветов, а после этого преобразовать найденный цвет в оттенок серого, но так, чтобы отношения между получаемыми серыми красками на шкале цветов 256-цветной палитры сохранились. К сожалению, формул отображения палитры из 256 цветов в цвета RGB, используемые в dlib, я не нашел — и хоть когда-то я описывал способы такого преобразования, они меня не устраивали — и хотелось все-таки сделать это, но гораздо лучше и правильнее.
Преобразования и функции не находились, и я уже начал впадать в отчаяние и пытался сам вывести формулу (что потом мне все-таки удалось, но не суть), но тут мне просто пришла в голову мысль отвлечься и попробовать ряд экспериментов с приведением картинки в черно-белый вид…
Для начала, я хотел разобраться, а можно ли обратиться к цвету в dlib (напоминаю, цвет картинки — это тип Color4f), как к некой структуре, которая содержит компоненты r, g и b соответственно, а потом выяснить, как же мне загрузить в программу изображение для экзекуции. К счастью, на эти вопросы нашлись быстрые и простые ответы: да, действительно, я могу так обратиться к цвету, и более того, это один стандартных способов работы с такими структурами; загрузка картинки вообще элементарна и интуитивно понятна: функция load из модуля dlib.image способна загрузить изображение почти любого типа, и на выходе дать объект, типом которого можно считать абстрактный класс SuperImage.
Такие простые решения меня вдохновили, и я решив воспользоваться ими, сделал простой преобразователь любой картинки в черно белую, для чего я взял стандартное уравнение приведения яркости из системы RGB в яркость в терминологии палитры оттенков серого:
Y’ = 0.2126 * R + 0.7152 * G + 0.0722 * B;
Воспользовавшись этой формулой и вышеуказанными соображениями, я сделал простой класс, который позволит легко сконвертировать почти любую картинку в черно-белую (а-ля советские фотографии на паспорт и не только):
class BlackNWhite { private: import std.string; string filename; string filetype; SuperImage image; public: this(string inputFileName) { filename = inputFileName; filetype = filename[filename.lastIndexOf(".")..$]; image = load(inputFileName); } void convert() { auto outputFileName = filename.replace(filetype, "") ~ "_black_and_white.png"; for (int i = 0; i < image.width; i++) { for (int j = 0; j < image.height; j++) { auto sourcePixel = image[i, j]; auto intensity = 0.2126 * sourcePixel.r + 0.7152 * sourcePixel.g + 0.0722 * sourcePixel.b; image[i, j] = Color4f(intensity, intensity, intensity); } } image.savePNG(outputFileName); } }
Работает это хозяйство весьма просто: с помощью конструктора получаем такие важные для нас данные, как имя файла для издевательств, тип файла (который вырезается из имени файла, исходя из того факта, что последняя точка в его имени указывает на расширение — и потому сечение строки, взятое по индексу этой последней точки до конца строки — это и есть расширение, или тип файла) и само изображение (загружаем его с помощью функции load). Всю работу в классе делает метод convert, который переделывает имя файла, исключая из него тип и добавляя отличительный признак наших сконвертированных файлов — часть имени « _black_and_white » и расширение «.png» (такая процедура неолбходима для сохранения результатов преобразований, поскольку, на текущий момент dlib умеет сохранять только в PNG), после чего и начинается вся реальная работа — берется отдельный пискель изображения и к нему применяется формула пересчета яркости, результат которой используется как новое значение для цвета того же самого пикселя.
Как видите, ничего сложного: просто двойной цикл прохода и элементарнейшее математическое преобразование, а какой результат:


А запускается преобразование так:
BlackNWhite bnw = new BlackNWhite(<путь до файла>); bmw.convert();
Также, ради интереса можно устроить массированную обработку изображений в одной папке, например, как сделал я, готовя эту статью (множество фоток, для того, чтобы выбрать самую классную):
void main() { import std.algorithm : each; each!(a => (new BlackNWhite("/home/aquaratixc/Загрузки/tests/" ~ a)).convert())(["a.jpg", "b.jpg", "c.jpg", "d.jpg"]); }
Благодаря Тимуру Гафарову, разработчику dlib, обработка изображений стала куда проще и занятнее, за что ему огромное спасибо — и я надеюсь, что в будущем, в dlib появится сохранение и других типов файлов изображений).
В черно-белых фотографиях есть свой неповторимый шарм, ностальгия какая то накатывает. Спасибо за инфу как сделать из обычной черно-белую.