Автор
|
Тема: Цветную картинку в черне-белую
|
SUnteXx |
опубликован 27-11-2001 11:12 MSK
Как можно плавно картинку (8 и более бит цвета) переаемти а черно-белую (оттенки серого)! Плавно означает что не сразу черно-белую сделать, а за 60, к примеру, шагов, ползков, пражков и т.д.?
|
MaxAGG
|
опубликован 27-11-2001 19:36 MSK
Лобовое решение:Сначала для каждого пиксела нужно вычислить его яркость. Правильно это делать по формуле 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
Не, я, конечно, все понимаю, что эта вся процедура долгая, но не на столько же!Картинка 300x200x32 переводилась в черно-белую так долго, что ... А может есть альтернативы, т.е. какой-нить другой способ перевода? Подскажите, плз! |
DmitryRyvkin
|
опубликован 28-11-2001 07:21 MSK
2MaxAGG: Надо бы еще учесть разную чувствительность глаза к цветам 2SUnteXx : Странно. Вы на XT делали ? Или случаем не SetPixel - GetPixel |
DmitryRyvkin
|
опубликован 28-11-2001 08:17 MSK
Sorry, не въехал что вам надо много шагов. Тогда действительно медленовато для мультика
|
MaxAGG
|
опубликован 28-11-2001 09:34 MSK
Да, вот я нашел более правильную формулу и без 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
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
2DmitryRyvkin: К сожалению, пока, GetPxel - SetPixel! А как еще можно, не подскажите? Самому брать цвет из памяти (без ГетПиксель'я) и туда же сразу же прописовать новое значение?Я правильно понял!? Если нет, то направте на путь истинный! |
MaxAGG
|
опубликован 28-11-2001 14:35 MSK
Обычно подобного рода операции делаются внутри битмапа, после чего он рисуется функцией, ну скажем, StretchDBits. Если битмап уже есть - то вперед, если нет, надо его сначала откуда-то сграбить. Примеры, если покопаться, лежат на этом сайте.To Rodion: Это всего лишь формула. То что удобнее в диапазоне 0...255 это подразумевалось по умолчанию.
|
Sourcer
|
опубликован 28-11-2001 15:45 MSK
Если есть точка с компонентами 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
2SUnteXx ну да именно так, через GetBitmapBits или GetDIBits2MaxAGG " Долго это сколько? У меня такая картинка вращается и масштабируется с Anti-Aliasing'ом за 100 миллисекунд (на древнем как дерьмо мамонта MMX 233). Может ты чего лишнего делаешь? " пришлите исходник плиз. У меня на таком же компе такая скорость вращение не выходила |
SUnteXx
|
опубликован 30-11-2001 01:28 MSK
Если не сложно, то скажите, плз, как мне по адресу такому-то прописать, допустим, число 15! Я уже совсем все позабыл, идей нет, все мозги пропиты давно, ...!З.Ы. У меня есть биты картинки Bits! Как мне изменить цвет 27 точки? SetPixel(...) не катит - долго получится изменять все пиксели! Как можно самому изменить цвет n-ной точки? |
DmitryRyvkin
|
опубликован 30-11-2001 05:59 MSK
А поэкспериментировать лень ? Грузиш битмэп (или есть его 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
To DmitryRyvkin: Я планирую включить это все в AGG (см. тред про библиотеку векторной графики). Пока можешь посмотреть демы (увы, только в .exe) на http://antigrain.hypermart.net Исходники пришлю где-нибудь через неделю-полторы - они очень старые и совсем непричесанные в таком виде - стыдно. Сейчас, через пару часов отбываю в отпуск на Key West - 20 часов рулить еще.
|
SUnteXx
|
опубликован 01-12-2001 01:02 MSK
Люди добрые, напишите, плз, пример, а то тяжеловато мне с этим, идей больше нет! Как мне в Bits+x записать число i (где Bits - поинтер на битмап( void *), x - смещение на n-ный пиксель(int), i - цвет(COLORREF))? |
SUnteXx
|
опубликован 02-12-2001 00:18 MSK
Люди, хелп, плз! Это важно! Ответьте кто может, плззз! |
Kosha
|
опубликован 02-12-2001 02:57 MSK
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
Согласен с предыдущим оратором, тоже и я говорил, правда на устаревшей ф-ции. Что делаеш то ? Если уж после таких объяснений не разобрался. Напиши, подскажу что надо. Недавно с этим плотно работал |
SUnteXx
|
опубликован 03-12-2001 00:27 MSK
Я не понимаю, как мне заменить, к примеру, 17 точку в картинке! Помогите, кто может, приведите пример на АПИ! ПЛЗ! |
SUnteXx
|
опубликован 05-12-2001 11:35 MSK
???Так кто-нить знает, как можно (если у нас есть поинтер) запихать по этому поинтеру переменную? Хелп, плз, а то неучем и останусь!( |
DmitryRyvkin
|
опубликован 05-12-2001 00:15 MSK
Не понял ... То есть есть int *ptr надо записать по нему переменную :-OO ?????????? Дык *ptr = myIntVar;
|
DmitryRyvkin
|
опубликован 05-12-2001 00:23 MSK
PS а для 17-го инта будет *(ptr+17) = myIntVar :-) Все таки я наверное не понял вопроса или прикалывашся ?
|
Kosha
|
опубликован 05-12-2001 21:48 MSK
2Suntexx:В приведенном коде: после GetDiBits: Bits[17].rgbtBlue=... Bits[17].rgbtRed=... Bits[17].rgbtGreen=... и все... Можно просто через MemMov, можно просто структуру из трех, короче, как удобнее потом SetDiBits от этого же. |
Kosha
|
опубликован 05-12-2001 21:48 MSK
P.S. А почему я такой пьяный? |
SUnteXx
|
опубликован 06-12-2001 02:06 MSK
Ура, получилось, правда скорость меня не радует!Померял сколько по времени займет процедура по переделыванию цветной картинки 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
Без комментариев! ОК! Пасиба!) |
Alvengo
|
опубликован 10-12-2001 13:55 MSK
Вот ты все понял, а у меня осталась пара вопросов. 1. SendMessage() - это хорошо, но у меня нет уверенности, что отрисовка будет производится каждый раз. Винды умеют сливать несколько пейнтов в один... 2. Выражение типа (br - r). А что, среднее всегда больше компоненты?! Почему здесь не может отрицательного числа получиться? 3. (float)iStep - преобразовывай сразу в дабл, все равно это делать придется... 4. Опять же sqrt(r*r + g*g + b*b)... r у тебя типа байт. А как у нас с переполнением при умножении?В общем обычно "правильная" прога почему-то не работает, а тут совсем наоборот, если верить тебе, что это работает...
|
SUnteXx
|
опубликован 11-12-2001 00:09 MSK
:) Пасибо за комментарии, посмотрим и подправим! Но вот скорость не катит, а так перерисовывает каждый раззз!ХР, как никак, тоже работает (и даже радует!), так что ... |