На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> PaintBox
    Привет всем!
    У меня задача, сделать по сути многофункциональную рисовалку на основе PaintBox.
    Подскажите, где много хорошей инфы лежит? :)
      trosh - какую рисовалку - векторную или растровую?
        Цитата Coala @
        trosh - какую рисовалку - векторную или растровую?

        за неделю с векторами точтно не успею, растровую бы успеть. В добавок там MDI приложение, еще с форточками поковыряться надо время выделить. Инструментарий обработать.. :wacko:
          Цитата
          Простые алгоритмы работы с изображением

          Цвета.

          Для написания хорошего графического редактора, необходимо добавить такую простую функцию, как фильтр. Он позволяет изменить какие-то свойства изображения.

          Давайте посмотрим, какие фильтры можно применить к цветам картинки. Первым делом нам необходимо получить массив пикселей, для дальнейшей работы с ними. Так как цветовые фильтры требуют работы с каждым отдельным пикселем, в нашем коде будет использоваться цикл, перебирающий пиксели и пременяющий фильтр:
          Подготовочные действия
          Цикл перебора по X, Y
          Применение формулы
          Конец цикла и заключительные действия

          Итак: подготовительные действия

          ExpandedWrap disabled
                Byte* ptr; //Это объявление необходимо только для первого способа перебора
                Image->PixelFormat = pf24bit; // Наиболее оптимальный формат пикселей для наших фильтров
                StatusBar1->SimpleText = "Подождите пожалуйста";

          В VCL существует два варианта циклов перебора:
          ExpandedWrap disabled
             for(int y = 0; y < Image->Height; y++){ //Перебор строк
                        ptr = (Byte*)Image->ScanLine[y]; //Получение текущей строки пикселей
                        for (int x = 0; x < Image->Width * 3; x+=1) { //Перебор каждого пикселя из строки
                        //RGB:
                        ptr[x] = ... //Красный
                        ptr[x+1] = ... //Зеленый
                        ptr[x+2] = ... //Синий
             }

          Этот способ достаточно быстрый, однако, при его использовании могут возникать некоторые проблемы. Второй способ проще для понимания:
          ExpandedWrap disabled
            for(int y = 0; y < Image->Height; y++){ //Перебор строк
                   for (int x = 0; x < Image->Width; x++) { //Перебор каждого пикселя из строки
                     Image->Pixels[x][y] = ... //Красный + зеленый + синий
                   }
            }

          Рассмотрим сначала затемнение о осветление пикселей. В системе цветов RGB черным является цвет 0,0,0, а белым 255,255,255. Таким образом, при затемнении, каждый канал пиксела стремиться к 0,0,0 способом декрементирования. Также, следует учитывать тот факт, что если канал имеет значение 0, Декрементировать его нет смысла. Вот итоговый алгоритм:
          ExpandedWrap disabled
                for(int y = 0; y < Image->Height; y++){
                        ptr = (Byte*)Image->ScanLine[y];
                        for (int x = 0; x < Image->Width * 3; x++) {
                           //Особое внимание на 3 бита на одну точку- Image->Canvas->Width * 3
                           if(ptr[x] > 10) ptr[x] = (Byte)(ptr[x] - 10);
                     }
                     }

          Полная версия алгоритма обладает одной интересной особенностью: по причине того, что над каждым каналом каждого пикселя совершается одно и тоже действие, полный цикл затемнения отличается от приведенного выше, однако, более оптимизированным считается код, выполняемый за меньшее число итераций. Вот оптимизированная версия алгоритма:
          ExpandedWrap disabled
                for(int y = 0; y < Image->Height; y++){
                        ptr = (Byte*)Image->ScanLine[y];
                        for (int x = 0; x < Image->Width * 3; x+=3) {
                           //Особое внимание на 3 бита на одну точку- Image->Canvas->Width * 3
                           if(ptr[x] > 10 && ptr[x+1] > 10 && ptr[x+2] > 10) {
                                ptr[x] = (Byte)(ptr[x] - 10);
                                ptr[x+1] = (Byte)(ptr[x+1] - 10);
                                ptr[x+2] = (Byte)(ptr[x+2] - 10); }
                     }
                     }

          Аналогичен код осветления:
          ExpandedWrap disabled
                for(int y = 0; y < Image->Height; y++){
                        ptr = (Byte*)Image->ScanLine[y];
                        for (int x = 0; x < Image->Width * 3; x+=3) {
                           //Особое внимание на 3 бита на одну точку- Image->Canvas->Width * 3
                           if(ptr[x] < 245 && ptr[x+1] < 245 && ptr[x+2] < 245) {
                                ptr[x] = (Byte)(ptr[x] + 10);
                                ptr[x+1] = (Byte)(ptr[x+1] + 10);
                                ptr[x+2] = (Byte)(ptr[x+2] + 10); }
                     }
                     }

          Можно также привести изображение к определенному оттенку. Для этого необходимо изменить соотношение между каналами. Например, если вы хотите сделать так, чтобы каждый канал содержал только оттенки красного, надо рассчитать среднее значение между тремя каналами, а затем установить каналы G и B в 0, а R в полученное значение:
          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]   = 0;
                           ptr[x+1] = 0;
                           ptr[x+2] = color;
                     }
                     }

          Фильтрация "Оттенки серого" установливает значения всех каналов пикселя в одинаковые значения. Таким образом, все каналы уравновешены, и не добавляют в цвет пикселя "примеси".
          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;
                     }
                     }

          И, наконец, последний фильтр: "Инвертация цветов".
          ExpandedWrap disabled
                     for(int y = 0; y < Image->Height; y++){
                        ptr = (Byte*)Image->ScanLine[y];
                        for (int x = 0; x < Image->Width * 3; x+=3) {
                           ptr[x] = (Byte)(256 - ptr[x]);
                           ptr[x+1] = (Byte)(256 - ptr[x+1]);
                           ptr[x+2] = (Byte)(256 - ptr[x+2]);
                     }
                     }

          Примечание: в данной статье представлены неоптимизированные версии алгоритмов. Наиболее узкими местами являются: использование промежуточных переменных и постоянное использование свойств Image->Width и Image->Height в цикле, для них рекомендуется исользовать промежуточные переменные, желательно типа register.

          Цитата
          Фильтра "Оттенки серого" установливает значения всех каналов пикселя в одинаковые значения.

          Почитай про конвертацию RGB->YUV и забудь про среднее арифметическое.

          Как Paint'е реализовано распыление и карандаш

          В OnMouseMove ;)

          Распыление
          ExpandedWrap disabled
                int x0, y0;
                for(float i=1;i<BrushRad; i++) {
                for(float f=1;f<360; f+=0.2) {
                 if(rand()>16384) {
                   x0 = X+cos(f)*i;
                   y0 = Y+sin(f)*i;
                   Image->Canvas->Pixels[x0][y0] = Image->Canvas->Brush->Color;
                 }
                }
                }

          Карандаш

          ExpandedWrap disabled
                      Image->Canvas->Pen->Mode = pmCopy;
                      Image->Canvas->LineTo(X, Y);

          Сообщение отредактировано: Old -
            Old, не надоело портянки не по делу развешивать? trosh'а в первую очередь интересует
            -как загрузить картинку
            -как ее отмасштабировать
            -как что-то дорисовать
            -как что-то стереть
            -как восстановить предыдущую копию

            trosh, посмотри тут. Хоть и на Дельфях, но поможет.
            ЗЫ - мой первый пост в том топике просто проигнорируй, читай дальше.
            Сообщение отредактировано: Coala -
              Цитата Coala @
              Old, не надоело портянки не по делу развешивать? [b]

              Old, ты гений! :)


              У меня готов графический просмоторщик, там все читаемые файлы разбираются по расширениям, в итоге создается Bitmap, который и отображается в Image.
                Цитата Coala @
                Old, не надоело портянки не по делу развешивать? trosh'а в первую очередь интересует

                Злая ты сегодня какая-то, коала \m/

                -как загрузить картинку

                хотя бы так:
                ExpandedWrap disabled
                  Picture.LoadFromFile
                  Image1.Picture.Assign(Clipboard)


                -как ее отмасштабировать
                ExpandedWrap disabled
                  //да, Coala, Ваш любимый ОР
                  var B,L: TBitmap;
                        R: TRect;
                  begin
                    L:=TBitmap.Create;// create source bitmap
                    L.Assign(TBitmap(Image1.Picture));//get bitmap from picture
                    B:=TBitmap.Create; // create buffer
                    B.Width:=200; //new width
                    B.Height:=100; //new height
                    R.Left:=0;
                    R.Top:=0;
                    R.Right:=B.Width-1;
                    R.Bottom:=B.Heigh-1;
                    B.Canvas.StretchDraw(R,L);//redraw buffer from source
                    Image1.Picture:=TPicture(B);//set new bitmap to the picture
                    B.Free;//destroy resources
                    L.Free;//destroy resources
                  end;


                -как что-то дорисовать
                ExpandedWrap disabled
                  DrawFocusRect


                -как что-то стереть
                ExpandedWrap disabled
                  CreateRegion


                -как восстановить предыдущую копию
                сохранить - потом восстановить, типа, да?
                  Цитата Old @
                  как восстановить предыдущую копию
                  сохранить - потом восстановить, типа, да?

                  Можно массив указателей завести, скажем из пяти, и по мере изменения Bitmap, добавлять новый и убивать самый старый.
                  Можно все это не в памяти хранить.... ;)
                    а кто против-то...
                      Никто не против.. :)
                      В выходные буду делать.
                        удачи
                          Цитата Old @
                          Злая ты сегодня какая-то, коала \m/
                          К тому же это старый Мяутовский текст, содержащий неверные алгоритмы обработки(например, оттенки серого считаются вовсе не так), который(текст) где-то здесь болтается. Так что достаточно было бы дать ссылку.
                            trainer, orb его переработал: http://www.sources.ru/magazine/0805/paint.html ;)
                              Цитата trainer @
                              Цитата Old @
                              Злая ты сегодня какая-то, коала \m/
                              К тому же это старый Мяутовский текст, содержащий неверные алгоритмы обработки(например, оттенки серого считаются вовсе не так), который(текст) где-то здесь болтается. Так что достаточно было бы дать ссылку.

                              Не помню я ссылок, сохраненные когда-то страницы с Исходников лежат кучей где-то...
                              Мне проще копи-пейстом...
                              А это:
                              PS: Этот вопрос неоднократно поднимался на форуме.
                              Вверху страницы есть кнопка ПОИСК
                              мне надоело вставлять - ленивых здесь море, все равно будут упорно не обращать на этот совет внимания.
                                Old
                                Самое гдавное в посте trainer'а, конечно же предпочел не заметить :whistle:
                                Цитата trainer
                                К тому же это старый Мяутовский текст, содержащий неверные алгоритмы обработки(например, оттенки серого считаются вовсе не так), который(текст) где-то здесь болтается. Так что достаточно было бы дать ссылку.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0549 ]   [ 16 queries used ]   [ Generated: 12.06.25, 20:16 GMT ]