Преобразуем изображения и GIF анимацию в код для Arduino


Сейчас в продаже доступно много разных Ч/Б дисплеев, в том числе и OLED. Для того, чтобы получить красивое черно-белое изображение для этих дисплеев, с глубиной цвета всего 1 бит, но в тоже время с имитацией полутонов, как на представленной ниже картинке — нужно использовать преобразование по алгоритму «Floyd-Steinberg».
image-loader.svg

Я, наверное, Вам уже надоел своими конвертерами, но не спешите с оценкой. Этот конвертер, в отличие от предыдущих, может преобразовать изображение любого масштаба и с любой глубиной цвета в требуемый размер и сразу получить на выходе готовый Си код понятный Arduino IDE или другому компилятору.

Можно, конечно, использовать графический редактор со встроенной функцией дизеринга Floyd-Steinberg, но ради пары картинок, нет желания изучать функционал этого сложного ПО. Да и как правило эти редакторы в основном платные. По этому я представляю он-лайн инструмент для конвертирования изображений полного цикла, с возможностью подстраивать детализацию выходного изображения.

Для примера загружаю изображение автомобиля в онлайн конвертер. При помощи ползунков «Яркость» и «Контрастность» добиваюсь максимально детализированного изображения на предпросмотре. На выходе получаю Ч/Б картинку с заданными мною параметрами разрешения и исходный код этого изображения. Полученный код можно скопировать и вставить в свой проект.
uqrvnb47m0jmup0t4qrjjf1pjyo.jpeg

Пошаговая инструкция для преобразования


1 — Выберите изображение на своем ПК, нажав на кнопку «Выберите фаил» и загрузите его в он-лайн конвертер. Изображение может быть цветным или ч/б с любой глубиной цвета и любого размера.

2 — Укажите требуемый размер получаемого на выходе преобразователя изображения.

3 — При помощи бегунков «Яркость» и «Контрастность добейтесь наилучшего результата на предварительном просмотре.

4 — Укажите название изображения латинскими буквами.

5 — Скопируйте полученный Си код и вставьте его в свой исходник.

6 — При необходимости сохраните преобразованное изображение, нажав на изображении правую кнопку мышки.

Преобразование GIF-анимации


Для реализации ардуино проекта, мне понадобилась черно-белая GIF-анимация. В интернете я нашел простой, пакетный способ преобразования картинок. Которым я с Вами, с удовольствием, делюсь. Ссылка на автора.
Для конвертирования GIF-ок в черно-белый формат. Потребуется приложение IrfanView. Скачиваем и устанавливаем его на свой ПК.

image-loader.svg

Запускаем приложение и загружаем в него GIF-ку. Потом жмем на кнопку меню «Сервис >> Извлечь все кадры». После чего приложение извлечёт из ГИФ-ки все кадры изображений и сохранит их в той же папке, в которой находится сам файл анимации.
Следующим шагом нужно преобразовать все кадры анимации в черно-белые картинки, с требуемым для дисплея размером. Для этого жмём в меню «Файл >> Преобразовать». Или кнопку «B» на клавиатуре.

image-loader.svg

Сначала нужно указать, в какой формат нужно преобразовать, для этого нажимаем кнопку «Обработка»
И активируем все параметры, которые отмечены на скриншоте ниже.

_bbcelqulx4yka9uab7al2qpzqo.jpeg

После чего выделяем все ранее преобразованные картинки и жмем кнопку «Добавить». И следом кликаем на кнопку «Выполнить». После чего, в этой же папке появятся преобразованные ч/б изображения.

quezof95nsrprutaeplrsiuxxr8.jpeg

Для преобразования картинок в код, понятный компилятору, нужно скачать приложение OledAnimation
и положить его в папку с ч/б изображениями. В этой папке не должно быть других изображений кроме тех, которые мы конвертируем. После запуска приложения все файлы, находящиеся в папке будут проконвертированы.

inuurmcrtkqqt_d16zelawwrlb8.jpeg

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

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

image-loader.svg

Подключаем дисплей к Ардуино


Для проверки анимации, понадобятся следующие компоненты:
Arduino nano
OLED SH1106
Провода соединительные

Соединяем дисплей с Arduino по следующей схеме:
k64kklwuvbqy2g0yvwef8sh0lbw.jpeg

Скетч для Ардуино


Скетч настолько простой, что даже комментировать в нем особо нечего.
Для воспроизведения анимации я вызываю простейшую функцию и предаю ей все требуемые параметры. Такие как: размер изображения по горизонтали и вертикали, длительность показа кадров, количество кадров в анимации, число повторов воспроизведения, имя массива указателей и цвет изображения, который в данном случае может принимать всего 2 значения: черный или белый. Учитывая не большой объем памяти программ контроллера ATmega328. Нужно учесть, что прокручивать в одном скетче несколько анимаций практически невозможно. Хотя если эти анимации будут маленького размера и с небольшим количеством кадров, то можно попробовать их запихнуть.
Для скетча так же потребуется библиотеки OLED_SH1106 и Adafruit-GFX
Так же можно скачать весь ардуино проект со всеми изображениями.

#include
#include

#include «chayka.h»
#include «butterfly.h»
#include «fish.h»
#include «snow.h»

//массивы указателей. В каждом массиве находятся указатели на все кадры анимации
//static const uint8_t * butterfly[] = { b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 };
static const uint8_t * chayka[] = { c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16 };
//static const uint8_t * fish[] = { f1, f2, f3, f4, f5, f6, f7, f6, f5, f4, f3, f2 };
//static const uint8_t * snow[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12 };

OLED_SH1106 display (-1); // если на дисплее нет пина res то -1

void setup ()
{
display.begin (SH1106_SWITCHCAPVCC, 0×3c); // Инициализация дисплея с I2C адресом 0×3C
}

void loop ()
{
animatoin_view (64, 63, 0, sizeof (chayka)/2, 4, chayka, true);
}

void animatoin_view (uint8_t anim_widht, uint8_t anim_height, uint16_t anim_delay, uint8_t anim_frame, uint8_t anim_repeat, const uint8_t * const anim_n[], boolean inv)
{
display.invertDisplay (inv); //инверсия экрана
for (uint8_t j = 0; j{
for (uint8_t i = 0; i{
display.clearDisplay (); // очистить видео буфер
display.drawBitmap ((128-anim_widht)/2, (64-anim_height)/2, anim_n[i], anim_widht, anim_height, 1); // загрузить указанный кадр анимации в видеобуфер
display.display (); // отобразить на экране дисплея данные из видеобуфера
delay (anim_delay); // задержка между кадрами
}
}
display.invertDisplay (false); //отключить инверсию экрана
}

Спасибо за то, что прочитали до конца. Если у Вас остались вопросы, то можете задать их в комментариях под статьёй.

© Habrahabr.ru