На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
  
> Как сделать черно-белое изображение
    Имеется цветной рисунок нужно из него сделать черно-белый.
    <_<
      ExpandedWrap disabled
                 int r = 0, g = 0, b = 0, color = 0;
                 for(int y = 0; y < Image->Height; y++){
                    ptr = (Byte*)Image->ScanLine[y];
                    for (int x = 0; x < Image->Width * 3; x+=3) {
                       r = ptr[x];   //Получаем
                       g = ptr[x+1]; //значения
                       b = ptr[x+2]; //каналов
                       color = (r + g + b) / 3; //Выссчитываем среднее значение
                       ptr[x]   = color;
                       ptr[x+1] = color;
                       ptr[x+2] = color;
                 }
                 }

      (с) Мяут ;)
        Noer, этот вариант неправильный. Правильно - использовать компоненту Y(яркость) кодировки YUV.
        Примеры - здесь: http://sources.ru/builder/faq/027.html или здесь: RGB to YUV и обратно
          trainer, Ну код же вроде пашет, а с ссылок этих я например не понял как сделать серую картинку...
            Цитата

            int r = 0, g = 0, b = 0, color = 0;
            for(int y = 0; y < Image->Height; y++){
            ptr = (Byte*)Image->ScanLine[y];
            for (int x = 0; x < Image->Width * 3; x+=3) {
            r = ptr[x]; //Получаем
            g = ptr[x+1]; //значения
            b = ptr[x+2]; //каналов
            color = (r + g + b) / 3; //Выссчитываем среднее значение
            ptr[x] = color;
            ptr[x+1] = color;
            ptr[x+2] = color;
            }
            }

            Мне кажется, что это преобразование не в черно-белое, а в серое.

            Цитата

            а с ссылок этих я например не понял как сделать серую картинку...

            Солидарен c NoeR
              Вообщето в моем понимание серое это считаеться черно-белое или тебе надо чисто только черный и только белый ?
                Цитата NoeR @
                Ну код же вроде пашет
                Он использует неправильный алгоритм определения яркости(оттенка серого).
                  Да, мне надо чисто только черный и только белый.
                    Черно-белый:

                    (Можно и через сканлайны)
                    ExpandedWrap disabled
                       int Height =  Image->Picture->Bitmap->Height;
                       int Width =  Image->Picture->Bitmap->Width;
                       byte Luminance = 128;
                       byte Color[3];
                       byte ColorMid;
                       for(int y = 0; y < Height; y++) {
                          for(int x = 0; x < Width; x++) {
                           Color[0] = GetRValue(Image->Picture->Bitmap->Canvas->Pixels[x][y]);
                           Color[1] = GetGValue(Image->Picture->Bitmap->Canvas->Pixels[x][y]);
                           Color[2] = GetBValue(Image->Picture->Bitmap->Canvas->Pixels[x][y]);
                           ColorMid = Gray(ptr[x], ptr[x+1], ptr[x+2]);
                           if(ColorMid < Luminance) Image->Picture->Bitmap->Canvas->Pixels[x][y] = 0x000000;
                           else Image->Picture->Bitmap->Canvas->Pixels[x][y] = 0xFFFFFF;
                          }
                       }


                    Оттенки серого:

                    ExpandedWrap disabled
                        int Height =  Image->Picture->Bitmap->Height;
                       int Width =  Image->Picture->Bitmap->Width*3;
                       byte ColorMid;
                       byte* ptr;
                       for(int y = 0; y < Height; y++) {
                          ptr = (byte*) Image->Picture->Bitmap->ScanLine[y];
                          for(int x = 0; x < Width; x+=3) {
                           ColorMid = Gray(ptr[x], ptr[x+1], ptr[x+2]);
                           ptr[x+2] = ColorMid;
                           ptr[x+1] = ColorMid;
                           ptr[x] = ColorMid;
                          }
                       }


                    Где Gray определено как Y:
                    ExpandedWrap disabled
                      #define Gray(R, G, B) (R*.257 + G*.504+B*.098+16.)


                    ЗЫ. NoeR, стравьте копирайты ;)
                      Цитата
                      ЗЫ. NoeR, стравьте копирайты

                      У Вас слишком высокая самооценка, я поставил копирайт!
                        Сори. Просто тут совсем запарился. Извини - больще не повториться ;)
                          Цитата Мяут-Настоящий @
                          Где Gray определено как Y:
                          #define Gray(R, G, B) (R*.257 + G*.504+B*.098+16.)
                          У фотошопа есть отличия притом я их вижу невооруженным глазом
                          Фотошоп сделал более контрастно
                            Цитата gastroler @
                            Да, мне надо чисто только черный и только белый.

                            А свойство TBitmap::Monochrome в true не пробовал выставить?
                              Подскажите, пожалуйста, недоделанному программисту, если это код перевода цветного изображения в оттенки серого:
                              int Height = Image->Picture->Bitmap->Height;
                              int Width = Image->Picture->Bitmap->Width*3;
                              byte ColorMid;
                              byte* ptr;
                              for(int y = 0; y < Height; y++) {
                              ptr = (byte*) Image->Picture->Bitmap->ScanLine[y];
                              for(int x = 0; x < Width; x+=3) {
                              ColorMid = Gray(ptr[x], ptr[x+1], ptr[x+2]);
                              ptr[x+2] = ColorMid;
                              ptr[x+1] = ColorMid;
                              ptr[x] = ColorMid;
                              }
                              }

                              То, где окончание? То есть как на форму вывести результат - фото в оттенках серого?
                                Цитата Klaribel @
                                Подскажите, пожалуйста,

                                Тут подразумевается, что на форме есть уже компонент Image, в него уже загружена картинка, а этот код вставлен в обработчик кнопки.
                                  Хм, ну это понятно. Расскажу подробней.
                                  У меня есть компоненты Image1 и Image2 и есть кнопка, по нажатию которой картинка Image1 должна становиться серой и выводиться в Image2.
                                  Вставляю код в обработчик кнопки и.... из Image1 исчезает картинка, в Image2 ничего не появляется. Подразумеваю, что что-то все таки не так)
                                    Ну можно вот так попробывать сделать ч\б. ТОлько по непонятной причине ч\б становится только часть фото.
                                    ExpandedWrap disabled
                                        int Lowpass(BYTE Image[][256], int x, int y)
                                      {
                                              int Mask[3][3] = {{1, 1, 1,}, {1, 1, 1}, {1, 1, 1}};
                                              int i, j, sum=0;
                                       
                                              for (j=-1; j<=1; j++)
                                                      for (i=-1; i<=1; i++)
                                                            sum += Image[x+i][y+j]*Mask[i+1][j+1];
                                              return INT(sum/9.0);
                                      }
                                      void __fastcall TForm1::Button1Click(TObject *Sender)
                                      {
                                         BYTE ImageData[256][256], *LinePtr;
                                              BYTE Output[256][256];
                                              int x, y;
                                       
                                              
                                              for (y=0; y<=255; y++)
                                              {
                                                      LinePtr = (BYTE *) Image1->Picture->Bitmap->ScanLine[y];
                                                      for (x=0; x<=255; x++)
                                                              ImageData[x][y] = LinePtr[x];
                                              }
                                            
                                              for (y=1; y<=254; y++)
                                                      for (x=1; x<=254; x++)
                                                              Output[x][y] = Lowpass(ImageData, x, y);
                                              
                                              for (y=0; y<=255; y++)
                                              {
                                                      LinePtr = (BYTE *) Image1->Picture->Bitmap->ScanLine[y];
                                                      for (x=0; x<=255; x++)
                                                              LinePtr[x] = Output[x][y];
                                              }
                                              Image1->Refresh();
                                      }
                                    Сообщение отредактировано: Kamenev_D -
                                      Спасибо за идею, однако не получается.
                                      Выскакивает окно

                                      project project1.exe raised exception class EInvalid Graphic Operation with message "Scan line index out of range". Process stopped....
                                        Цитата Klaribel @
                                        Выскакивает окно

                                        Загрузи фото другого размера. И обязательно bmp
                                          А если мне именно надо jpg и именно такого размера (160х128)?=)
                                            ну попробуй сначала загрузить bmp такого размера
                                              Ну да, bmp и большего размера прога обрабатывает, но действительно только маленькую часть. С jpg, пределанный в bmp и большего, и такого же размера работать отказывается:(
                                                Кстати, я так и не понял почему не обрабатывается вся фото. Выдернул кусок кода из проекта просто. Но раньше то работал же.
                                                Может кто-то подскажет почему так происходит.
                                                  Если в Image1 загружен не bmp-формат (jpg, png и т.д.) то можно просто скопировать эту картинку в промежуточный bmp, его "засерить" и заасайнить его уже в Image2.

                                                  ExpandedWrap disabled
                                                      // копирование в промежуточный bitmap
                                                      Graphics::TBitmap* bitmap = new Graphics::TBitmap();
                                                      bitmap->Width = Image1->Width;
                                                      bitmap->Height = Image1->Height;
                                                      BitBlt(bitmap->Canvas->Handle, 0, 0, bitmap->Width, bitmap->Height, Form1->Canvas->Handle, Image1->Left, Image1->Top, SRCCOPY);
                                                     
                                                      // "засеривание" промежуточного bitmap'а
                                                      bitmap->PixelFormat = pf24bit;
                                                      for (int y = bitmap->Height - 1; y >= 0; --y)
                                                      {
                                                        TRGBTriple* scanLine = (TRGBTriple*)bitmap->ScanLine[y];
                                                        for (int x = bitmap->Width - 1;  x >= 0; --x)
                                                        {
                                                          const BYTE gray = 0.222 * scanLine[x].rgbtRed +
                                                                            0.707 * scanLine[x].rgbtGreen +
                                                                            0.071 * scanLine[x].rgbtBlue;
                                                          scanLine[x].rgbtGreen = gray;
                                                          scanLine[x].rgbtRed = gray;
                                                          scanLine[x].rgbtBlue = gray;
                                                        }
                                                      }
                                                     
                                                      // копирование промежуточного bitmap'а в Image2
                                                      Image2->Picture->Assign(bitmap);
                                                      delete bitmap;


                                                  Но если картинка не на форме (а на панели например, к канве которой доступа напрямую нет) или поверх картинки какие-то контролы - то тогда сложнее будет.

                                                  Добавлено
                                                  Цитата Kamenev_D @
                                                  Кстати, я так и не понял почему не обрабатывается вся фото

                                                  У тебя вообще какой-то код кучерявый.. Какие-то три цикла и почему только до 255(254)?!

                                                  Добавлено
                                                  о.. прикольно. Знаю как прорисовать Image в любой девайсконтекст (именно прорисовать а не скопировать уже прорисованный).
                                                  вместо
                                                  ExpandedWrap disabled
                                                    BitBlt(bitmap->Canvas->Handle, 0, 0, bitmap->Width, bitmap->Height, Form1->Canvas->Handle, Image1->Left, Image1->Top, SRCCOPY);

                                                  надо просто
                                                  ExpandedWrap disabled
                                                    Image1->Perform(WM_PAINT, (WPARAM)bitmap->Canvas->Handle, 0);

                                                  и отпадает проблема парента, и возможных контролов поверх картинки... Image1 вообще невидимым может быть!

                                                  Добавлено
                                                  Так-с...
                                                  После всего вышло что можно и вообще без промежуточного битмапа :D
                                                  Сразу прорисовать Image1 в Image2 и потом последний "засерить":
                                                  ExpandedWrap disabled
                                                      Image2->Picture->Bitmap->PixelFormat = pf24bit;
                                                      Image2->Picture->Bitmap->Width = Image1->Width;
                                                      Image2->Picture->Bitmap->Height = Image1->Height;
                                                      Image1->Perform(WM_PAINT, (WPARAM)Image2->Picture->Bitmap->Canvas->Handle, 0);
                                                     
                                                      for (int y = Image2->Picture->Bitmap->Height - 1; y >= 0; --y)
                                                      {
                                                        TRGBTriple* scanLine = (TRGBTriple*)Image2->Picture->Bitmap->ScanLine[y];
                                                        for (int x = Image2->Picture->Bitmap->Width - 1;  x >= 0; --x)
                                                        {
                                                          const BYTE gray = 0.222 * scanLine[x].rgbtRed +
                                                                            0.707 * scanLine[x].rgbtGreen +
                                                                            0.071 * scanLine[x].rgbtBlue;
                                                          scanLine[x].rgbtGreen = gray;
                                                          scanLine[x].rgbtRed = gray;
                                                          scanLine[x].rgbtBlue = gray;
                                                        }
                                                      }


                                                  Работает :)
                                                    Всем спасибо, завтра попробую, сегодня уже сил нет=)
                                                      Спасибо огромное! РАБОТАЕТ! :D
                                                        подскажите ещё одному начинающему программисту, возможно ли провернуть фильтр сепии?
                                                        пробовал менять формулу серого на формулу коричневого и сепии, но как-то не очень получалось... подскажите плиз)

                                                        Добавлено
                                                        откуда формула серого такая? #define Gray(R, G, B) (R*.257 + G*.504+B*.098+16.) есть формулы других цветов?
                                                          Цитата donotlies @
                                                          откуда формула серого такая? #define Gray(R, G, B) (R*.257 + G*.504+B*.098+16.) есть формулы других цветов?
                                                          Откуда там у тебя +16. - это нам не известно. Это очевидно вычисление яркости точки, отображать ее можно в оттенках хоть серого, хоть красного или зеленого. Каких таких других цветов?
                                                            Цитата donotlies @
                                                            откуда формула серого такая? #define Gray(R, G, B) (R*.257 + G*.504+B*.098+16.)

                                                            А от куда ты ее взял?
                                                            На Википедии приведены такие весовые коэффициенты: 0,222 0,707 и 0,071
                                                              donotlies
                                                              Это история старая. Во времена когда создавалось телевидение...

                                                              Во общем формула отсюда.
                                                              http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf

                                                              Chow
                                                              Википедия не достоверный источник. Но такая формула тоже существует.

                                                              А по поводу того какая из них правильная отвечу просто. Во первых не понятно откуда взялась картинка и формат её хранения и способ вывода. Так что с успехом можно применять любую. Но вроде как стандарт CIE преобладает. Так что надо следовать ихним рекомендациям.
                                                                я её взял с первой страницы этой темы...
                                                                  Цитата Klaribel @
                                                                  А если мне именно надо jpg и именно такого размера (160х128)?=)

                                                                  Для *.jpg можна использовать TJPEGImage.

                                                                  #include <Jpeg.hpp>
                                                                  //-----------------
                                                                  TJPEGImage *tJpg=new TJPEGImage;
                                                                  //-----------------
                                                                  1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                                  0 пользователей:


                                                                  Рейтинг@Mail.ru
                                                                  [ Script execution time: 0,0626 ]   [ 15 queries used ]   [ Generated: 5.07.25, 14:16 GMT ]