перевод 24 разрядного изображения в 16 (5-6-5)

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

всем Котам МЯУ!!! вот получилось у мну работать с картой памяти(ATmega32, LCD LS020). решил вывести на дисплей рисунок BMP. описание нашел, откуда начинать считывать - нашел. http://jenyay.net/Programming/Bmp но вот надо преобразовать 24 бита в 16 формата 5-6-5. прошу кинуть в меня ссылкой, алгоритмом. если кинете в меня код - не обижусь)))
радиоэлектроника - жизнь моя...
Аватара пользователя
Satyr
Друг Кота
Сообщения: 7439
Зарегистрирован: Чт ноя 04, 2010 01:56:36
Откуда: г. Москва

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение Satyr »

#define RGB24TOLCD(val) (((val & 0x00f80000) >> 8 ) | ((val & 0x0000fc00) >> 5) |((val & 0x000000f8) >> 3))

Это если экран у тебя RGB берет. Еще BGR популярно :))
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

:)) спрасиб огромное!!!!!!!!!!! вот сделал чтение текстовых файлов, захотелось и изображений тоже. правда на расжатие jpeg уже памяти МК не хватает, а на BMP еще попробую)))
радиоэлектроника - жизнь моя...
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Сообщение avreal »

«Ну вот опять»™
Приблизительно как в теме про преобразование текста в число
Такой #define выглядит красиво, но работает далеко от оптимального. Двигает слишком много.

Вот полный функциональный аналог макроса. Почти не думая записанный не в одну строку, зато с учетом того, что часть сдвигов полезна для других:

Код: Выделить всё

#include <stdint.h>

#define RGB24TOLCD(val) (((val & 0x00f80000) >> 8 ) | ((val & 0x0000fc00) >> 5) |((val & 0x000000f8) >> 3))

uint16_t rgb24to16(uint32_t rgb24)
{
        return RGB24TOLCD(rgb24);
}

uint16_t rgb24to16a(uint32_t rgb24)
{
        uint16_t rgb16;
        rgb24 >>= 3;
        rgb16 = rgb24 & 0x1F;
        rgb24 >>= 2;
        rgb16 |= rgb24 & (0x3F << 5);
        rgb24 >>= 3;
        rgb16 |= rgb24 & (0x1F << 11);
        return rgb16;
}
avr-gcc -Os -c -Wa,-al=rgb.txt -mmcu=atmega32 rgb.c
Итого первая функция занимает 102 байта, вторая -- 66. И время выполнения будет приблизительно в два раза меньше (около полусотни тактов вместо около сотни). Это при компиляции на размер. Если на скорость (-O2), то размер и время первой функции не меняются. Вторая становится на два байта длиннее, зато время выполнения тактов на шесть сокращается (второй сдвиг делается не циклом на два прохода, а линейным кодом).
Листинг компилятора цепляю.
rgb.txt
(3.8 КБ) 189 скачиваний

Хотя, конечно, как раз в этом месте аккуратная ассемблерная вставочка не помешала бы. Как умеет gcc -- не ломая оптимизацию С-шного кода. Причём если в ней объединить и вывод на SPI, то преобразование вообще не будет занимать времени, будет делаться во время вывода предыдущего пиксела. Так на глаз, без написания кода, это тактов пятнадцать, не больше.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

avreal, и все кто знает - вопрос))) есть у меня буфер обьявленный как

Код: Выделить всё

unsigned char buf[512];

допустим там лежат байты

Код: Выделить всё

{0x00, 0x00, 0x00, ... , 0x00}


для хранения пикселя объявляю 32-разрядную переменную

Код: Выделить всё

unsigned long data;

тут будет {0x00000000} либо {00000000.00000000.00000000.00000000} //вроде посчитал 32)))
нужно buf[0] записать в 3-й "байт" data, buf[1] во 2-й "байт" data и buf[1] - в первый)))

правильно ли я составил конструкцию которая эту чтуку реализует?

Код: Выделить всё

data=((buf[0]<<15)|(buf[1]<<7)|(buf[2]<<0));


правильно ли я понимаю свою же задачу?
Последний раз редактировалось demonchik Вс авг 14, 2011 12:21:57, всего редактировалось 1 раз.
радиоэлектроника - жизнь моя...
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

потом data пихать так думаю в uint16_t rgb24to16a(uint32_t rgb24)

Код: Выделить всё

rgb24to16a(data);
радиоэлектроника - жизнь моя...
Аватара пользователя
Satyr
Друг Кота
Сообщения: 7439
Зарегистрирован: Чт ноя 04, 2010 01:56:36
Откуда: г. Москва

Re:

Сообщение Satyr »

avreal писал(а):Такой #define выглядит красиво, но работает далеко от оптимального. Двигает слишком много.

Смотря на чем. Это под 32 бит процессор.
Под 8 битном, возможно, чисто на оптимизатор компилятора надеяться не стоит.
Аватара пользователя
Satyr
Друг Кота
Сообщения: 7439
Зарегистрирован: Чт ноя 04, 2010 01:56:36
Откуда: г. Москва

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение Satyr »

Под 8бит целесообразней функцию вобще на манипуляцию над отдельными байтами переложиь, даюе без int16
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

и вот еще интьересно - МК не будет делать смещения в file_1.buf[i]? - ведь тогда будет переполнение... годится ли такая конструкция для записи в дата со смещением без изменения file_1.buf[]?

Код: Выделить всё

 uint32_t data=(((file_1.buf[0])<<15)|((file_1.buf[1])<<7)|((file_1.buf[2])<<0));
радиоэлектроника - жизнь моя...
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: Re:

Сообщение avreal »

Satyr писал(а):
avreal писал(а):Такой #define выглядит красиво, но работает далеко от оптимального. Двигает слишком много.
Смотря на чем. Это под 32 бит процессор.
Хоть и там, и там есть буквы «32», всё же не оно :)))
demonchik писал(а):всем Котам МЯУ!!! вот получилось у мну работать с картой памяти(ATmega32, LCD LS020).
Для АРМ-а, у которого сдвиги практически "на шару" -- согласен, тот #define неплох.

Satyr писал(а):Под 8 битном, возможно, чисто на оптимизатор компилятора надеяться не стоит.
Да нужно просто правильно объяснить ему, что нужно сделать с данными. Хотя тут правильнее будет выписать на асме преобразование вместе с выводом в SPI. Маленькая функция, которая всё сильно ускорит.

Satyr писал(а):Под 8бит целесообразней функцию вобще на манипуляцию над отдельными байтами переложиь, даюе без int16
Пробовал и для входа, и для выхода union из uint32_t / uint16_t и соответствующих байтовых массивов. Чтобы манипулировать байтами, а заносить в union из входного 32-битного и возвращать из union из 16-битного. Оказалось даже слегка хуже, чем вторая функция.
Думаю, лучше в цикле по пикселам побайтно по указателю вынимать отдельные цвета и нужное форимровать. Но это «вообще не тот #define», а я хотел сравнить именно «красивую» запись и ориентированную на 8-битник.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение avreal »

demonchik писал(а):для хранения пикселя объявляю 32-разрядную переменную

Код: Выделить всё

unsigned long data;
тут будет {0x00000000} либо {00000000.00000000.00000000.00000000} //вроде посчитал 32)))
нужно buf[0] записать в 3-й "байт" data, buf[1] во 2-й "байт" data и buf[1] - в первый)))
правильно ли я составил конструкцию которая эту чтуку реализует?

Код: Выделить всё

data=((buf[0]<<15)|(buf[1]<<7)|(buf[2]<<0));
См. выше -- лучше вообще указателем побайтно идти. Просто зная, что байты лежат в таком-то порядке.

Код: Выделить всё

    uint8_t *ptr = buf;
    for( идём по пикселам ) {
        // смещениями к указателю выбираем RGB
        uint16_t rgb565 = ((ptr[0] & 0xF8) << 8) | (ptr[1] >> 3); //
        rgb565 |= (ptr[1] & 0xFC) << 3; // G
        // выводим
        // смещаем указатель на 3 байта
        ptr += 3;
    }
Никакие промежуточные 32-битные переменные не нужны. Только зря туда-сюда ползать.
Красивее это можно записать так:

Код: Выделить всё

    typedef struct {
        uint8_t r, g, b; // или какой там порядок в буфере
    } rgb888_t;
    rgb888_t *pixels = (rgb888_t*)buf; // мапим массив структур на массив байтов
    for( идём по пикселам ) {
        // смещениями к указателю выбираем RGB
        // я не знаю, какой порядок на входе и на выходе, это так, намёк
        // 16-битная переменная тут и для AVR может оказаться лучше, так как сдвиг на 8
        // с большой вероятностью компилятор превратит в один mov, а вот зелёный, который
        // разносится на два байта, может обработаться лучше.
        uint16_t rgb565 = ((pixels->r & 0xF8) << 8) | (pixels->b >> 3);
        rgb565 |= (pixels->g & 0xFC) << 3;
        // выводим
        // смещаем указатель на размер структуры, переходим к следующему пикселу
        ++pixels;
    }
Код на AVR должен получиться такой же.
Недостаток -- на чём-то тольще 8-битника нужно думать про упаковку структур, компилятор не должен добавлять лишних байтов в структуру для выравнивания на слово. Платформо-зависимо, так что лучше врукопашную по байтам идти.
Ну и если думать про оптимальность, то лучше rgb565 объявить как uint_fast16_t, тогда на том же ARM-е будет заведена 32-битная переменная и построен код получше.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение avreal »

Думаю, лучше всего основной цикл реализовать как

Код: Выделить всё

    uint8_t *ptr = buf;
    for( по пикселам ) {
        out_to_lcd( ptr[2], ptr[1], ptr[0]); // или какой там порядок
        ptr += 3;
    }
Функция void out_to_lcd(uint8_t r, uint8_t g, uint8_t b); должна сразу и сдвигать и выводить в индикатор. Плюсы:
1) При смене индикатора на имеющий цвет 8/8/8 эта часть не меняется.
2) При работе через SPI можно подготовить первый байт, послать, потом двигать/маскировать данные для второго байта и послать его. Еще и ожидания готовности SPI ставить перед выводом уже готового байта. Сильно ускорит процесс.

Поначалу функцию написать «как понятно», чтобы убедиться, что все работает.
Потом уже оптимизировать, inline от C99 поможет, а может, ассемблерную вставку в ней сделать -- это по месту смотреть.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

спасиб, хлопцы за направление на путь истинный)))
радиоэлектроника - жизнь моя...
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

наверно так
Код:

Код: Выделить всё

    uint8_t *ptr = buf;
    for( идём по пикселам ) {
        // смещениями к указателю выбираем RGB
        uint16_t rgb565 = ((ptr[0] & 0xF8) << 8) | ((ptr[2]&0xF8) >> 3); //
        rgb565 |= (ptr[1] & 0xFC) << 3; // G
        // выводим
        // смещаем указатель на 3 байта
        ptr += 3;
    }

действительно, расписав все по битам понял что к чему. спасибо!!!
радиоэлектроника - жизнь моя...
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение avreal »

demonchik писал(а):

Код: Выделить всё

        uint16_t rgb565 = ((ptr[0] & 0xF8) << 8) | ((ptr[2]&0xF8) >> 3);

Для ptr[2] >> 3 маскирование не нужно, при сдвиге вправо эти биты всё равно уйдут за край.
Главное, чтобы слева не вдвинулось чего не надо, но это гарантируется для беззнакового числа (заполнение нулями слева при сдвиге вправо). Так что (ptr[2] >> 3) & 0x1F тоже не нужно.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

наваял я такую чтуку

Код: Выделить всё

void BMP_show(unsigned char x, unsigned char y, unsigned char w, unsigned char h)
{
int i;
uint16_t rgb565;
uint8_t *ptr=&file_1.buf[54];

 lcd_c(0xEF90);
 lcd_c(0x0504);
 lcd_c(0x0800+y);
 lcd_c(0x0900+y+h-1);
 lcd_c(0x0A00+DISP_H-x-w);
 lcd_c(0x0B00+DISP_H-x-1);
 
if ((res=f_open(&file_1,"0:/AMANDA.BMP",FA_READ)) == FR_OK)
 do
 {
 res=f_read(&file_1,file_1.buf,sizeof(file_1.buf)-1,&nbytes);   
     for(i=0;i<(nbytes/3);i++)
    {
 
        rgb565 = (((ptr[2] & 0xF8) << 8) | ((ptr[0] & 0xF8) >> 3)); //   R B
        rgb565 |= (ptr[1] & 0xFC) << 3; // G
    //имеем rgb565 формата RRRRRGGGGGGBBBBB   5-6-5
    // выводим
    lcd_d(rgb565);

    // смещаем указатель на 3 байта
        ptr += 3;
    }   
   
   
 }while(res==FR_OK/*|| nbytes == sizeof(file_1.buf)*/);

но выводит только первую строку изображения(даже верно). по коду смотрю - вроде норма(( не могу понять своего затыка.
Последний раз редактировалось demonchik Пн авг 15, 2011 23:28:55, всего редактировалось 3 раза.
радиоэлектроника - жизнь моя...
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

заметил что в

Код: Выделить всё

for(i=0;i<([color=#FF4040]nbytes/3[/color]);i++) 

nbytes/3 - это только в случае если не первая итерация цикла.... в первой итерации

Код: Выделить всё

(nbytes-ofset)/3
- тогда число может быть не целое. кажется изображение будет искаженным....
радиоэлектроника - жизнь моя...
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

и с do while я намутил)))
- работает)) только бы сдвиг байт бы устранить)) а так весь дисплей заливает)))
радиоэлектроника - жизнь моя...
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

свершилось чудо!!!
Вложения
DSC04711.jpg
(158.27 КБ) 309 скачиваний
радиоэлектроника - жизнь моя...
Аватара пользователя
demonchik
Встал на лапы
Сообщения: 94
Зарегистрирован: Вт апр 07, 2009 13:39:13
Откуда: одесса
Контактная информация:

Re: перевод 24 разрядного изображения в 16 (5-6-5)

Сообщение demonchik »

нашел тему - http://www.circuitidea.com/Article/DIY- ... 0PLUS.html
тут достаточно инфы, чтоб все получилось (по примеру делал)
радиоэлектроника - жизнь моя...
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»