Автор
|
Тема: Из 24 -> 8
|
Rechkin |
опубликован 27-12-2001 18:52 MSK
Как преобразовать 24битное изображение в 8битное Исходные данные: массив unsigned char размерности ImageWidth x ImageHeight x 3 Я вроде понимаю, что каждый пиксель предствлен 3 байтами, переписываю исходную матрицу как средневзвешанное всех цветов, но ни чего нае выходит!
|
Rechkin
|
опубликован 27-12-2001 23:19 MSK
Ответье, пожалуйс |
Drunkard
|
опубликован 28-12-2001 02:27 MSK
8-бит это 256 цветов. Насколько мне известно, в BMP файле используется таблица цветов и математической функции переводящей из 24-бит в 8-бит нету. Т.е. если мне не изменяет память все 256 цветов заданы в самом ВМР файле. Насчет 16 цветов я уверен на все 100%. Приходилось преобразовывать 24-битное изображение в 4-битное. Я поступал так. На бумажке нарисовал единичный куб, оси координат которого есть R G и B. В 24-битном представлении 8-бит это R, следующие 8 - G, последние 8- B. Точный порядок не помню :(. Тем самым мы имеем точку, которая принадлежит этому кубу. Нужно определиться с границами разных цветов в этом кубе и в зависимости от попадания точки в границы, назначать урезанный цвет. Я уверен, что эта задача решена, но где взять решение не знаю. Для 16 цветов, я решал ее самостоятельно. |
ADK
|
опубликован 28-12-2001 07:49 MSK
Насколько я понимаю, это весьма нетривиальная задача. Нужно подобрать оптимальную палитру. Здесь я думаю, сплошная математика. Photoshop при индексировании цветов предлагает много вариантов, только интересно, насколько трудно хотя бы один самому сделать? |
Rechkin
|
опубликован 28-12-2001 08:47 MSK
А для 16 как решается? |
ADK
|
опубликован 28-12-2001 09:42 MSK
Ну, это большая разница. Если 256 цветов вполне конкурентноспособный формат при правильно подобранной палитре, то 16 стандартных цветов - это полная туфта. Я не пробовал преобразовывать, но думаю, дело решит обычная таблица сопоставляения цветов - ведь 16 - не так уж и много. Если 24-bit цвет принадлежит какому-либо диапазону (выбери 16 диапазонов), то преобразуй его в один из 16-ти цветов. |
Rechkin
|
опубликован 28-12-2001 13:49 MSK
Пробою сделать вот - так //Для перевода 24 -> 8 вычисляем среднегеометрическое деленое на 3 for (i =0; i < BufferLength; i++){ for (j=0; j < 3;j++){ temp += pow(Sourse [3*i+j],2); } Normal[i] = (unsigned char)sqrt(temp/3); temp = 0; } Но ничего не выходит,хотя в matcad все работает! |
Drunkard
|
опубликован 29-12-2001 05:07 MSK
Вот тебе готовое решение для 16 цветов. Честно скажу, что бился я над ним почти месяц. Подгонял цвета по вышеописанному кубику. Если же возьмешься за 256 цветов - я тебе не завидую! Видимо, поэтому и не публикуется данный алгоритм, уж больно много трудов положили, небось, чуваки. Кто может предложить решение отличное от моего - буду рад воспользоваться :-))BYTE PreobrColor(BYTE R,BYTE G,BYTE B) { if(((B+B-G-R)<=0)&&((G+G-B-R)<=0)&&((G+B-R)<=0)) if(R>191) return (BYTE)0x0C;// Red else return (BYTE)0x04;// Red Dark else if(((B+B-G-R)>0)&&((B-G-G)>=0)&&((R-B)>=0)) if(R>191) return (BYTE)0x0D;// Red + Blue else return (BYTE)0x05;// Red + Blue Dark else if(((G+G-B-R)>0)&&((G-B-B)>=0)&&((R-G)>=0)) if(R>191) return (BYTE)0x0E;// Red + Green else return (BYTE)0x06;// Red + Green Dark if(((G+G-B-R)<=0)&&((R+R-G-B)<=0)&&((R+G-B)<=0)) if(B>191) return (BYTE)0x09;// Blue else return (BYTE)0x01;// Blue Dark else if(((G+G-B-R)>0)&&((G-R-R)>=0)&&((B-G)>=0)) if(B>191) return (BYTE)0x0B;// Blue + Green else return (BYTE)0x03;// Blue + Green Dark else if(((R+R-B-G)>0)&&((R-G-G)>=0)&&((B-R)>=0)) if(B>191) return (BYTE)0x0D;// Red + Blue else return (BYTE)0x05;// Red + Blue Dark if(((R+R-G-B)<=0)&&((B+B-G-R)<=0)&&((B+R-G)<=0)) if(G>191) return (BYTE)0x0A;// Green else return (BYTE)0x02;// Green Dark else if(((R+R-B-G)>0)&&((R-B-B)>=0)&&((G-R)>=0)) if(G>191) return (BYTE)0x0E;// Red + Green else return (BYTE)0x06;// Red + Green Dark else if(((B+B-R-G)>0)&&((B-R-R)>=0)&&((G-B)>=0)) if(G>191) return (BYTE)0x0B;// Green + Blue else return (BYTE)0x03;// Green + Blue Dark if((R>223) |
Drunkard
|
опубликован 29-12-2001 05:09 MSK
Из-за болтовни не уместилось. Попробую еще.BYTE PreobrColor(BYTE R,BYTE G,BYTE B) { if(((B+B-G-R)<=0)&&((G+G-B-R)<=0)&&((G+B-R)<=0)) if(R>191) return (BYTE)0x0C;// Red else return (BYTE)0x04;// Red Dark else if(((B+B-G-R)>0)&&((B-G-G)>=0)&&((R-B)>=0)) if(R>191) return (BYTE)0x0D;// Red + Blue else return (BYTE)0x05;// Red + Blue Dark else if(((G+G-B-R)>0)&&((G-B-B)>=0)&&((R-G)>=0)) if(R>191) return (BYTE)0x0E;// Red + Green else return (BYTE)0x06;// Red + Green Dark if(((G+G-B-R)<=0)&&((R+R-G-B)<=0)&&((R+G-B)<=0)) if(B>191) return (BYTE)0x09;// Blue else return (BYTE)0x01;// Blue Dark else if(((G+G-B-R)>0)&&((G-R-R)>=0)&&((B-G)>=0)) if(B>191) return (BYTE)0x0B;// Blue + Green else return (BYTE)0x03;// Blue + Green Dark else if(((R+R-B-G)>0)&&((R-G-G)>=0)&&((B-R)>=0)) if(B>191) return (BYTE)0x0D;// Red + Blue else return (BYTE)0x05;// Red + Blue Dark if(((R+R-G-B)<=0)&&((B+B-G-R)<=0)&&((B+R-G)<=0)) if(G>191) return (BYTE)0x0A;// Green else return (BYTE)0x02;// Green Dark else if(((R+R-B-G)>0)&&((R-B-B)>=0)&&((G-R)>=0)) if(G>191) return (BYTE)0x0E;// Red + Green else return (BYTE)0x06;// Red + Green Dark else if(((B+B-R-G)>0)&&((B-R-R)>=0)&&((G-B)>=0)) if(G>191) return (BYTE)0x0B;// Green + Blue else return (BYTE)0x03;// Green + Blue Dark if((R>223) |
Drunkard
|
опубликован 29-12-2001 05:10 MSK
Во, падла, не дает! Концовка, которая не уместилась:if((R>223) |
Drunkard
|
опубликован 29-12-2001 05:13 MSK
Наваждение какое-то! Ладно, высылаю в Си-шном варианте тебе на Мыло. |
Drunkard
|
опубликован 29-12-2001 05:19 MSK
Ага, понял, он вертикальную палку не пропускает! Знак логического "или" состоит из двух таких палок. Приведенный алгоритм довольно сносно хреначит из 24 бит в 4 бита. Для 8 бит тебе придется делать нечто подобное. Брось это дело, придумай, что-нибудь другое, типа оттенков серого, там все просто. Иначе я тебе не завидую :-)) |
Drunkard
|
опубликован 29-12-2001 05:54 MSK
Да, вот еще нашел, как она, эта процедура вызывается. // Выделим черный куб и преобразуем if((Red<65)&&(Green<65)&&(Blue<65)) tetrH=(BYTE)0x00; else tetrH=(BYTE)(PreobrColor(Red,Green,Blue)<<4);В ВМР файле при 24 битах цвета идут байты R,G потом B. При 32 - сначала незначащий байт, потом R,G,B. При 16 битах идут по 5 битов на цвет. Это так, для информации. |
Drunkard
|
опубликован 29-12-2001 06:11 MSK
Теоретическая база под всей этой ерундой (преобразование цвета) есть. Я это понял, когда бился над этим кубиком. Нужно исходить из того, что из общей точки, вершины трех осей координат построены три конуса, не полые. Конуса имеют три цвета R,G и В. Где-то они идут не смешиваясь и мы получаем чистый цвет, где-то пересекаются и получаем смесь, а по пространственной биссектрисе получим серый цвет. Также эти конуса порублены шестью плоскостями, с координатами 0(3 плоскости) и 255(3 плоскости). Вот нашелся бы умник, владеющий теорией множеств и расписал бы универсальный алгоритм попадания точки с координатами R,G,B в область пространства с таким-то цветом. :-)) |
Rechkin
|
опубликован 30-12-2001 19:00 MSK
Извини, за нетривиальную просьбу, но не мог бы ты выслать еще раз! Тут были проблемы с провайдером, вернее у него, за что тот жолго извинялся, поэтому за несколько дней почта потирялась. Заранее спасибо!
|
Drunkard
|
опубликован 31-12-2001 03:45 MSK
Выслал это тебе, также и на мыло //Дело в том, что прога написана для обработки любой цветовой гаммы, начиная от 4 бит и //кончая 32 битами, т.е. любым, которое может быть на экране. Вот кусок из нее, где идет //вызов ф-ии PreobrColor для 24битного цвета //здесь- lpBits - указатель на битовый массив в BitMape из которого читаем (исходный) //lpBits16 - указатель на битовый массив в 16 цветном BitMape в который пишем //В цикле идет обработка сразу двух пикселей, т.к. потом потетрадно пишется в байт. //Надеюсь, с созданием своих битмапов справишься :-)) //Написано корявенько, но работает на все 100 if(pbihU->biPlanes*pbihU->biBitCount==(WORD)24) { j=0; for(i=0;i<pbihU->biSizeImage;i+=(DWORD)6) { // Выделим черный куб и преобразуем if((*(lpBits+i)<65)&&(*(lpBits+i+1)<65)&&(*(lpBits+i+2)<65)) tetrH=(BYTE)0x00; else tetrH=(BYTE)(PreobrColor(*(lpBits+i),*(lpBits+i+1),*(lpBits+i+2))<<4); // Обрабатываем 2 пиксель if((*(lpBits+i+3)<65)&&(*(lpBits+i+4)<65)&&(*(lpBits+i+5)<65)) tetrL=(BYTE)0x00; else tetrL=PreobrColor(*(lpBits+i+3),*(lpBits+i+4),*(lpBits+i+5)); *(lpBits16+j)=tetrH|tetrL; // Загоняем в массив j++; }
|
Drunkard
|
опубликован 31-12-2001 04:01 MSK
Доплнение, в конце потерялась еще одна } В переменной j - при выходе из цикла получишь размер нового изображения ImageSize. |