WWW.ИСХОДНИКИ.РУ cpp.sources.ru
java.sources.ru web.sources.ru soft.sources.ru
jdbc.sources.ru asp.sources.ru api.sources.ru

  Форум на исходниках
  C / C++ / Visual C++
  Цветную картинку в черне-белую

СПРОСИТЬ  ОТВЕТИТЬ
профайл | регистрация | faq

Автор Тема:   Цветную картинку в черне-белую
SUnteXx опубликован 27-11-2001 11:12 MSK   Click Here to See the Profile for SUnteXx   Click Here to Email SUnteXx  
Как можно плавно картинку (8 и более бит цвета) переаемти а черно-белую (оттенки серого)! Плавно означает что не сразу черно-белую сделать, а за 60, к примеру, шагов, ползков, пражков и т.д.?
MaxAGG опубликован 27-11-2001 19:36 MSK     Click Here to See the Profile for MaxAGG  Click Here to Email MaxAGG     
Лобовое решение:

Сначала для каждого пиксела нужно вычислить его яркость. Правильно это делать по формуле

br = sqrt(r*r + g*g + b*b) * 0.577;

Но это медленно, можно упростить усреднением:

br = (((r + g) >> 1) + b) >> 1;

Это не очень правильно, но быстро.


Затем берем исходную картинку и копируем в "черно-белую" следующим образом:

r_bw = (br-r) * i / n + r;
g_bw = (br-g) * i / n + g;
b_bw = (br-b) * i / n + b;

где n - кол-во шагов, i - номер шага. Если кол-во шагов - степень 2, то тормозное деление можно заменить свигом.

Возможно что-то напутал, ну разберешься.

SUnteXx опубликован 28-11-2001 00:01 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Не, я, конечно, все понимаю, что эта вся процедура долгая, но не на столько же!

Картинка 300x200x32 переводилась в черно-белую так долго, что ...

А может есть альтернативы, т.е. какой-нить другой способ перевода? Подскажите, плз!

DmitryRyvkin опубликован 28-11-2001 07:21 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
2MaxAGG:
Надо бы еще учесть разную чувствительность глаза к цветам
2SUnteXx :
Странно. Вы на XT делали ? Или случаем не
SetPixel - GetPixel
DmitryRyvkin опубликован 28-11-2001 08:17 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
Sorry, не въехал что вам надо много шагов.
Тогда действительно медленовато для мультика
MaxAGG опубликован 28-11-2001 09:34 MSK     Click Here to See the Profile for MaxAGG  Click Here to Email MaxAGG     
Да, вот я нашел более правильную формулу и без sqrt (строго говоря, тоже не вполне правильная, но весьма хорошая):

double Intensity = .299 * Red + .587 * Green + .114 * Blue ;

Все значения - в диапазоне 0...1

------------------------------
Картинка 300x200x32 переводилась в черно-белую так долго, что ...</i>
------------------------------

Долго это сколько? У меня такая картинка вращается и масштабируется с Anti-Aliasing'ом за 100 миллисекунд (на древнем как дерьмо мамонта MMX 233). Может ты чего лишнего делаешь?


rodion опубликован 28-11-2001 00:40 MSK     Click Here to See the Profile for rodion  Click Here to Email rodion     
double Intensity = .299 * Red + .587 * Green + .114 * Blue ;
Red, Green, Blue, Intensity вовсе не обязателбно должны лежать в пределах 0..1 как в OpenGl
Для работы с Bmp более удобен диапазон 0..255.
А формула правильная.
SUnteXx опубликован 28-11-2001 14:08 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
2DmitryRyvkin: К сожалению, пока, GetPxel - SetPixel! А как еще можно, не подскажите? Самому брать цвет из памяти (без ГетПиксель'я) и туда же сразу же прописовать новое значение?

Я правильно понял!? Если нет, то направте на путь истинный!

MaxAGG опубликован 28-11-2001 14:35 MSK     Click Here to See the Profile for MaxAGG  Click Here to Email MaxAGG     
Обычно подобного рода операции делаются внутри битмапа, после чего он рисуется функцией, ну скажем, StretchDBits. Если битмап уже есть - то вперед, если нет, надо его сначала откуда-то сграбить. Примеры, если покопаться, лежат на этом сайте.

To Rodion:
Это всего лишь формула. То что удобнее в диапазоне 0...255 это подразумевалось по умолчанию.

Sourcer опубликован 28-11-2001 15:45 MSK     Click Here to See the Profile for Sourcer  Click Here to Email Sourcer     
Если есть точка с компонентами RGB, то

Y=0.36*R + 0.53*G + 0.11*B
R=G=B=Y
Стандаpт CCIR 601-1 (как в стандаpтной VGA-ой функции):
Gray=(299*Red+587*Green+114*Blue)/1000.

Стандаpт CCIR 709:
Gray=(213*Red+715*Green+72*Blue/1000.

Стандаpт ITU:
Gray=(222*Red+707*Green+71*Blue)/1000.


http://src.narod.ru/alg/alg8.html

DmitryRyvkin опубликован 29-11-2001 13:00 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
2SUnteXx ну да именно так, через GetBitmapBits или GetDIBits

2MaxAGG "
Долго это сколько? У меня такая картинка вращается и масштабируется с Anti-Aliasing'ом за 100 миллисекунд (на древнем как дерьмо мамонта MMX 233). Может ты чего лишнего делаешь? "
пришлите исходник плиз. У меня на таком же компе такая скорость вращение не выходила

SUnteXx опубликован 30-11-2001 01:28 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Если не сложно, то скажите, плз, как мне по адресу такому-то прописать, допустим, число 15! Я уже совсем все позабыл, идей нет, все мозги пропиты давно, ...!

З.Ы.
У меня есть биты картинки Bits! Как мне изменить цвет 27 точки? SetPixel(...) не катит - долго получится изменять все пиксели! Как можно самому изменить цвет n-ной точки?

DmitryRyvkin опубликован 30-11-2001 05:59 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
А поэкспериментировать лень ?
Грузиш битмэп (или есть его handle)
BITMAP InfoBmpStruct;
ASSERT(handleImage != NULL);
::GetObject((HBITMAP) handleImage, sizeof(BITMAP), &InfoBmpStruct);
totalPixels = InfoBmpStruct.bmHeight * InfoBmpStruct.bmWidth * (InfoBmpStruct.bmBitsPixel / 8);
Таперь знаеш сколько байт надо загрузить и формат бмп (обрати внимание - значения будут зависеть от ТЕКУЩЕГО видеорежима).
Далее
GetBitmapBits (handleImage, totalPixels, (void *) myMemBuffer;

Так вот в этом буфере и ставь нужные точки.
Хранится в нем бмп построчно, скажем если у тебя 16 бит highColor включен, а картинка 256*256, то середина самой верхней линии
будет 128 - ой по счету short int (!), те 256 - 257 char,
середина 2- ой строки
256 * 2 + 128 * 2 char и т д. Немного путанно с размером пикселя работать, но можно.
После всего пишеш из буфера назад в бмп
по SetBitmapBits.
Вобщем разберешся, тут на 10 минут работы


MaxAGG опубликован 01-12-2001 00:24 MSK     Click Here to See the Profile for MaxAGG  Click Here to Email MaxAGG     
To DmitryRyvkin:
Я планирую включить это все в AGG (см. тред про библиотеку векторной графики). Пока можешь посмотреть демы (увы, только в .exe) на http://antigrain.hypermart.net Исходники пришлю где-нибудь через неделю-полторы - они очень старые и совсем непричесанные в таком виде - стыдно. Сейчас, через пару часов отбываю в отпуск на Key West - 20 часов рулить еще.
SUnteXx опубликован 01-12-2001 01:02 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Люди добрые, напишите, плз, пример, а то тяжеловато мне с этим, идей больше нет! Как мне в Bits+x записать число i (где Bits - поинтер на битмап( void *), x - смещение на n-ный пиксель(int), i - цвет(COLORREF))?
SUnteXx опубликован 02-12-2001 00:18 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Люди, хелп, плз! Это важно! Ответьте кто может, плззз!
Kosha опубликован 02-12-2001 02:57 MSK     Click Here to See the Profile for Kosha  Click Here to Email Kosha     

HDC hTempDC;
HBITMAP hTempBmp;

BITMAPINFO bi;
RGBTRIPLE Bits[32][32];
RGBTRIPLE FBits[32][32];

int ReturnValue;

...................
//Init BitmapInfo
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth=32;
bi.bmiHeader.biHeight=32;
bi.bmiHeader.biPlanes=1;
bi.bmiHeader.biBitCount=24;
bi.bmiHeader.biCompression=BI_RGB;

//работаем с битами
//hTempDC - контекст устройства, куда выбран hTempBmp
ReturnValue=GetDIBits(hTempDC,hTempBmp,0,32,Bits,&bi,DIB_RGB_COLORS);

// Теперь Bits - массив, забитый структурами RGBTRIPLE


//Тут с ним работаешь, потом обратно:

SetDIBits(hFTempDC,hFTempBmp,0,32,FBits,&bi,DIB_RGB_COLORS);

BitBlt(hDesktopDC,CursorPosition.x,CursorPosition.y,
32,32,hFTempDC,0,0,SRCCOPY);

Вот собственно и все. Доработай по смыслу.

DmitryRyvkin опубликован 02-12-2001 10:28 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
Согласен с предыдущим оратором, тоже и я говорил, правда на устаревшей ф-ции. Что делаеш то ? Если уж после таких объяснений не разобрался. Напиши, подскажу что надо. Недавно с этим плотно работал
SUnteXx опубликован 03-12-2001 00:27 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Я не понимаю, как мне заменить, к примеру, 17 точку в картинке! Помогите, кто может, приведите пример на АПИ! ПЛЗ!
SUnteXx опубликован 05-12-2001 11:35 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
???

Так кто-нить знает, как можно (если у нас есть поинтер) запихать по этому поинтеру переменную? Хелп, плз, а то неучем и останусь!(

DmitryRyvkin опубликован 05-12-2001 00:15 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
Не понял ... То есть есть int *ptr надо записать по нему переменную :-OO
?????????? Дык *ptr = myIntVar;
DmitryRyvkin опубликован 05-12-2001 00:23 MSK     Click Here to See the Profile for DmitryRyvkin  Click Here to Email DmitryRyvkin     
PS а для 17-го инта будет *(ptr+17) = myIntVar :-)
Все таки я наверное не понял вопроса или прикалывашся ?
Kosha опубликован 05-12-2001 21:48 MSK     Click Here to See the Profile for Kosha  Click Here to Email Kosha     
2Suntexx:

В приведенном коде:

после GetDiBits:

Bits[17].rgbtBlue=...
Bits[17].rgbtRed=...
Bits[17].rgbtGreen=...

и все... Можно просто через MemMov, можно просто структуру из трех, короче, как удобнее

потом SetDiBits от этого же.

Kosha опубликован 05-12-2001 21:48 MSK     Click Here to See the Profile for Kosha  Click Here to Email Kosha     
P.S. А почему я такой пьяный?
SUnteXx опубликован 06-12-2001 02:06 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Ура, получилось, правда скорость меня не радует!

Померял сколько по времени займет процедура по переделыванию цветной картинки 1024х768х24b в картинку с оттенками серого (за 25 шагов) по формуле br = (222*r+707*g+71*b) / 1000. Я был поражен! 22.5 секунды с перересовкой окна после каждого шага и 21.3 секунды без перерисовки! Неужели это так долго делается или я где-нить ошибся? Померял скорость по другим формулам и пришел (т.е. приполз) к тому, что быстрее и, самое главное, эффективней будет формула:

sqrt(r*r + g*g + b*b) * 0.577 // (1024х768х24b 25 кадров) выполняется за 23.744 секунды;

Другие формулы как-то не правильно, на мой взгляд, переводят картинку, т.е., к примеру, у меня на картинке надпись красным цветом (0x00ff0000) на черном фоне (0x00000000), так вот эта надпись исчезает, т.е. в черно-белом виде становится такого же цвета, как и фон! (Красный перешел в черный. Компу больше не наливать!). Вот только по выше указанной формуле все делается более или менее пучком! Вот так!!! Может кто еще какие-нить формулы знает!:?

Скорость проверял на 730 PIII, 128 RAM, на WinXP (правда вынь (Вынь ХренРаботает) была не слишком, но загружена прогами, так что скорость уменьшается, но все же...)

Исходники могу выслать, если кому интерестно (хотя кому это может быть интересно, у всех свои проги - сори, мысли вслух!)

Вот кусок кода, который использует прога (посмотрите, может что-нить не так или что-нить надо подправить/изменить/удалить):

// Цикл, в котором выполняем изменение цвета битмапы (этот кусок из ф-ции создания окна, т.е. при мессаге WM_CREATE)

for (i = 1; i <= Steps; i++)
{
ColorToGray(BitmapBitsPtr, B.bmWidth, B.bmHeight, i);
SendMessage(hWnd, WM_PAINT, NULL, NULL);
}


// а вот сама ф-ция, которая обрабатывает битмап

void ColorToGray(void* BitmapBitsPtr, int iWidth, int iHeight, int iStep)
{
COLORREF clr;
double br;
BYTE r,g,b;
BYTE r1,g1,b1;
COLORREF *tmp;
tmp = (unsigned long *)BitmapBitsPtr;
for (int y = 0; y < iHeight; y++)
{
for (int x = 0; x < iWidth; x++)
{
clr = *tmp;
r = GetRValue(clr);
g = GetGValue(clr);
b = GetBValue(clr);

// Вот все формулы, которые я знаю (т.е. которые я видел (для данной задачи!) когда-либо)

// br = (222*r+707*g+71*b) / 1000;
br = sqrt(r*r + g*g + b*b) * 0.577;
// br = (((r + g) >> 1) + b) >> 1;
// br = (0.299 * r + 0.587 * g + 0.114 * b);
// br = 0.36*r + 0.53*g + 0.11*b;
// br = (213*r+715*g+72*b)/1000;


r1 = ceil((br - r) * ((float)iStep / (float)Steps) + r);
g1 = ceil((br - g) * ((float)iStep / (float)Steps) + g);
b1 = ceil((br - b) * ((float)iStep / (float)Steps) + b);


clr = RGB(r1,g1,b1);
// clr = (b1 << 16) + (g1 << 8) + r1; // Почему-то так прога медленней работает
*tmp = (COLORREF)clr;
tmp++;
}
}
}

SUnteXx опубликован 10-12-2001 00:01 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
Без комментариев! ОК! Пасиба!)
Alvengo опубликован 10-12-2001 13:55 MSK     Click Here to See the Profile for Alvengo  Click Here to Email Alvengo     
Вот ты все понял, а у меня осталась пара вопросов.
1. SendMessage() - это хорошо, но у меня нет уверенности, что отрисовка будет производится каждый раз. Винды умеют сливать несколько пейнтов в один...
2. Выражение типа (br - r). А что, среднее всегда больше компоненты?! Почему здесь не может отрицательного числа получиться?
3. (float)iStep - преобразовывай сразу в дабл, все равно это делать придется...
4. Опять же sqrt(r*r + g*g + b*b)... r у тебя типа байт. А как у нас с переполнением при умножении?

В общем обычно "правильная" прога почему-то не работает, а тут совсем наоборот, если верить тебе, что это работает...

SUnteXx опубликован 11-12-2001 00:09 MSK     Click Here to See the Profile for SUnteXx  Click Here to Email SUnteXx     
:) Пасибо за комментарии, посмотрим и подправим! Но вот скорость не катит, а так перерисовывает каждый раззз!

ХР, как никак, тоже работает (и даже радует!), так что ...

СПРОСИТЬ  ОТВЕТИТЬ
Перейти:


E-mail | WWW.ИСХОДНИКИ.RU

Powered by: Ultimate Bulletin Board, Freeware Version 5.10a
Purchase our Licensed Version- which adds many more features!
© Infopop Corporation (formerly Madrona Park, Inc.), 1998 - 2000.