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



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

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

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



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


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

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

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

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

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

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

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


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



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

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



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



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



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



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

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



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


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

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



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


Скетч настолько простой, что даже комментировать в нем особо нечего.

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

Для скетча так же потребуется библиотеки OLED_SH1106 и Adafruit-GFX
Так же можно скачать весь ардуино проект со всеми изображениями.

#include <Wire.h>
#include <OLED_SH1106.h>

#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, 0x3c);  // Инициализация дисплея с I2C адресом 0x3C  
}

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<anim_repeat; j++)
    {
           for( uint8_t i = 0; i<anim_frame; 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);  //отключить инверсию экрана
} 

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

Комментарии (19)


  1. Jury_78
    13.02.2022 12:20
    -2

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

    Есть и бесплатные... В ImageMagick можно, вроде в Gimp еще. Python pillow в конце концов.


    1. CyberBot Автор
      13.02.2022 12:26
      +2

      Я не нашел по ссылке как проконвертировать пакетно GIF анимацию


      1. Jury_78
        13.02.2022 13:01
        -2

        Не понял, что значит "пакетно" если у вас пара картинок? Если просто сделать из gif набор картинок png то это можно наити в ин-те, например так:

        convert -coalesce input_img.gif out_img%05d.png


        1. CyberBot Автор
          13.02.2022 13:10
          +1

          Преобразовать все кадры анимации в ч/б, Floyd-Steinberg вид и выдать Си код всей анимации одним файлом


          1. Jury_78
            13.02.2022 13:45
            -2

            Преобразовать все кадры анимации в ч/б, Floyd-Steinberg вид

            Используйте, например, ImageMagick для этого.

            выдать Си код всей анимации одним файлом

            Си код для ImageMagick это слишком, впрочем можно (в Linux) получить из картинки текстовый HEX файл, а название массива самому придется вводить.

            Но вы же говорили про "использовать графический редактор", а вот уже хотите Си код.


            1. kafeman
              13.02.2022 16:06

              Но вы же говорили про "использовать графический редактор", а вот уже хотите Си код.

              А что тут такого? Это очень многие графические редакторы "из коробки" умеют. Gimp, например, умеет.


              1. Jury_78
                15.02.2022 10:01
                -2

                Ну так, это хорошо. Автор наверно рад...


              1. CyberBot Автор
                15.02.2022 10:14
                +2

                Для одиночной картинки GIMP может сгенерировать код, но не в том виде который понимает библиотека GFX


                1. Jury_78
                  15.02.2022 11:38

                  Значит остается ImageMagick или python. Python имеет смысл использовать если знаком этот язык.


                  1. CyberBot Автор
                    15.02.2022 12:05

                    Для чего весь этот геморой? Я же предложил простой способ. Как для одиночных картинок https://duino.ru/media/image-converter/index.html

                    Так и для GIF-анимации https://duino.ru/media/animations.zip


                    1. Jury_78
                      15.02.2022 14:31

                      Вам не нравятся альтернативные методы?


                      1. CyberBot Автор
                        15.02.2022 18:11

                        У меня неполноценных методов есть с десяток, я же пытаюсь облегчить этот процесс.


                      1. Jury_78
                        15.02.2022 19:15

                        Кому то легче с командной строкой.


                      1. CyberBot Автор
                        15.02.2022 19:45

                        Мне все равно как, главное, что бы на это уходило минимум времени. Так как времени катострафически нехватает.


  1. Jury_78
    13.02.2022 13:44
    -2

    del


  1. fiego
    14.02.2022 18:04

    Я правильно понимаю, что проеобразованный в Си код содержит изображение построчно? И это для дисплея с внутренним по-колоночным буфером (по 8 бит в колонке)? То есть, мощность процессора у нас запасом?

    Я к чему -- если картинка размером по вертикали кратна 8 и выводится по вертикальной координате в кратную 8 позицию, то вывод битмапа можно существенно оптимизировать. Впрочем, оптимизировать тут можно в любом случае.


    1. CyberBot Автор
      15.02.2022 10:27
      +1

      К сожалению из-за совместимости с разными дисплеями, библиотека GXF настолько тупо написана, что она складывает байт изображения в видеобуфер по пиксельно, а потом из видеобуфера передает на дисплей и снова из пикселей формирует байт. Нужно свою функцию обмена с дисплеем писать


      1. fiego
        15.02.2022 15:00

        "Впрочем, оптимизировать тут можно в любом случае." -- я ж об этом и написал. У меня есть опыт программирования для SSD1306, который не сильно отличается от SH1106.

        Возвращаясь к тому, что я сказать хотел. Реорганизацией представления данных можно заметно повысить эффективность как по памяти, так и по быстродействию, мало ли что ещё надо делать микроконтроллеру в это же самое время. Если бы это было в статье, она была бы интереснее, с моей точки зрения. А так, мы просто обучились пользоваться несколькими приложениями.


        1. CyberBot Автор
          15.02.2022 18:13

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