Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> LockBits вместо SetPixel 
:(
    Опции темы
Georgich
Дата 3.2.2011, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Приветствую.

В общем, такая проблема. Есть метод отрисовки луча по пикселям:
Код

              private void DrawBeam(ref Bitmap bm)
              {
                  X = X0;
                  Y = Y0;
                  Random rand = new Random();
                  const double digitWeight = 360.0 / 65536;
                  double angle = ScanAngle * digitWeight;
                  double cos = Math.Cos(Math.PI * (90 - angle) / 180);
                  double sin = Math.Sin(Math.PI * (90 - angle) / 180);
       
                  for (int k = 0; k < 256; ++k)
                  {
                      X += cos;
                      Y -= sin;
                      //bm.SetPixel((int)Form1.X, (int)Form1.Y, Color.FromArgb(255, 255, 255));
                  }
       
                  for (int k = 256; k < 768; ++k)
                  {
                      int num = rand.Next(0, 255);
                      X += cos;
                      Y -= sin;
                      bm.SetPixel((int)X, (int)Y, Color.FromArgb(num, num, num));
                  }
              }

Отрисовывает он не особо-то и быстро. Решил попробовать заменить на LockBits. Сделал таким образом:
Код

        BitmapData bmpData;
        byte[] rgbValues = new byte[2400000];

        private void DrawBeam(ref Bitmap bm)
        {
            X = X0;
            Y = Y0;
            Random rand = new Random();
            const double digitWeight = 360.0 / 65536;
            double angle = ScanAngle * digitWeight;
            double cos = Math.Cos(Math.PI * (90 - angle) / 180);
            double sin = Math.Sin(Math.PI * (90 - angle) / 180);

            Rectangle rect = new Rectangle(0, 0, (int)width, (int)height);
            bmpData = bm.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            
            for (int a = 0; a < 768; a++)
            {
                if (a <= 256)
                {
                    X += cos;
                    Y -= sin;
                }
                else
                {
                    X += cos;
                    Y -= sin;
                    int num = rand.Next(0, 255);
                    rgbValues[(int)Y * bmpData.Stride + (int)X * 3] = (byte)num;
                    rgbValues[(int)Y * bmpData.Stride + (int)X * 3 + 1] = (byte)num;
                    rgbValues[(int)Y * bmpData.Stride + (int)X * 3 + 2] = (byte)num;
                }
            }

            Marshal.Copy(rgbValues, 0, bmpData.Scan0, rgbValues.Length);

            bm.UnlockBits(bmpData);
         }

И получил вообще тормоза. Дело в том, что он при отрисовки нужных мне пикселей, отрисовывает и остальные пиксели черным цветом. И так при каждой перерисовке. Можно ли этого как-то избежать? Может, действительно, LockBits будет пошустрее выводить тогда изображение? Спасибо.
PM MAIL   Вверх
Experimenter
Дата 7.2.2011, 14:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, если еще актуально...

Код

            for (int a = 0; a < 768; a++)
            {
                if (a <= 256)
                {
                    X += cos;
                    Y -= sin;
                }
                else
                {
                    X += cos;
                    Y -= sin;

                    int num = rand.Next(0, 255);
                    int offset = (int)Y * bmpData.Stride + (int)X * 3;
                    Marshal.WriteByte(bmpData.Scan0, offset, (byte)num);

                    offset = (int)Y * bmpData.Stride + (int)X * 3 + 1;
                    // и т.д.
                }
            }
            // Marshal.Copy(rgbValues, 0, bmpData.Scan0, rgbValues.Length);
            bm.UnlockBits(bmpData);


может, как-то так?


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
Georgich
Дата 7.2.2011, 15:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Experimenter, спасибо, что заглянули в тему.
Все так же тормозит. SetPixel пока превосходит данные пляски по скорости. Неиспользуемая часть битмапа отрисовывается черным цветом. И, так как она отрисовывается в каждом шаге, то и получаются тормоза.
Скорости отрисовки я стараюсь добиться максимальной, так как придется еще получать данные из usb на скорости около 25 Мб/сек, обработать эти данные и по ним уже отрисовать картинку.
PM MAIL   Вверх
Experimenter
Дата 7.2.2011, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, хм, думается, что проблема не в отрисовке, через LockBits должно работать быстрее
Я сделал замеры, и получается, что LockBits при первом вызове метода срабатывает раза в три быстрее, при последующих - примерно в 10 раз быстрее. Код:

Код

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap b = CreateBitmap();

            pictureBox1.Image = b;

            Stopwatch sw = new Stopwatch();
            sw.Start();

            DrawBeamSetPixel(b);

            sw.Stop();

            label1.Text = sw.ElapsedTicks.ToString();
        }

        private Bitmap CreateBitmap()
        {
            Bitmap b = new Bitmap(
                1000, 800, PixelFormat.Format24bppRgb);

            using (Graphics g = Graphics.FromImage(b))
            {
                g.Clear(Color.YellowGreen);

                g.DrawImage(b, 0.0f, 0.0f);
            }

            return b;
        }

        private void DrawBeamSetPixel(Bitmap bm)
        {
            int X = 0;
            int Y = 0;

            for (int k = 0; k < 768; k++)
            {
                X++;
                Y++;

                bm.SetPixel((int)X, (int)Y, Color.FromArgb(255, 255, 255));
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Bitmap b = CreateBitmap();

            pictureBox1.Image = b;

            Stopwatch sw = new Stopwatch();
            sw.Start();

            DrawBeamLockBits(b);

            sw.Stop();

            label1.Text = sw.ElapsedTicks.ToString();
        }

        private void DrawBeamLockBits(Bitmap bm)
        {
            int X = 0;
            int Y = 0;

            Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
            BitmapData bmpData = bm.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            for (int a = 0; a < 768; a++)
            {
                X++;
                Y++;

                int offset = Y * bmpData.Stride + X * 3;
                Marshal.WriteByte(bmpData.Scan0, offset, 122);

                offset++;
                Marshal.WriteByte(bmpData.Scan0, offset, 122);

                offset++;
                Marshal.WriteByte(bmpData.Scan0, offset, 122);
            }

            bm.UnlockBits(bmpData);
        }


Хотя и через SetPixel счет идет на миллисекунды, тормозов не наблюдаю. Судите сами.


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
Georgich
Дата 7.2.2011, 20:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Experimenter, спасибо за код. В скорости LockBits я убедился. Дабы не быть голословным в том, что в моем коде что-то тормозит, прикладываю исходники. Посмотрите их, пожалуйста, если вам не составит труда. Возможно, они прояснят то, что я пытаюсь объяснить.
P.S. Сейчас там сделано через LockBits, но если вы закомментируете этот кусок и расскоментируете кусок с SetPixel, то увидите разницу.

Спасибо.

Присоединённый файл ( Кол-во скачиваний: 6 )
Присоединённый файл  Sector.rar 43,15 Kb
PM MAIL   Вверх
Experimenter
Дата 8.2.2011, 09:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, посмотрел код. Вы в цикле лочите битмап, отсюда и задержки. Попробуйте вынести LockBits в обработку события Timer_Tick


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
neutrino
Дата 8.2.2011, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: 3
Всего: 62



А какая сама задача? Почему просто не воспользоваться GDI+? Или если надо самому по какой-то причине, то есть быстрые алгоритмы рисования линий. Начать можно с Брезенгама.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
Georgich
Дата 8.2.2011, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Experimenter, да, спасибо. Действительно надо было вынести в Timer_tick.
Но, остается другой вопрос: остальной фон - черный. Можно ли как-то от него избавится, чтобы его не перерисовывать?
PM MAIL   Вверх
Experimenter
Дата 8.2.2011, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, думаю, что битмап сначала нужно "нарисовать" в конструкторе или где-то еще до запуска таймера, ведь вы оперируете с BitmapData, и туда при блокировании битмапа передаются сплошные нули (черный цвет), если с битмапом ничего не делалось после его создания.


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
Georgich
Дата 8.2.2011, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Experimenter, так, вроде, в конструкторе формы я и отрисовываю:
Код

        Bitmap bmSector;
        BitmapData bmpData;
        DrawPicture drawSector;

        public Form1()
        {
            InitializeComponent();
            drawSector = new DrawPicture(ref pictureBox1);//(pictureBox1.Width, pictureBox1.Height);
            bmSector = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Rectangle rect = Rectangle.FromLTRB(0, 0, pictureBox1.Width, pictureBox1.Height);
            bmpData = bmSector.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            drawSector.DrawBeams(ref bmSector, ref bmpData);
            pictureBox1.Image = bmSector;
            pictureBox1.Invalidate();
            bmSector.UnlockBits(bmpData);
        }

Что-то не так?
PM MAIL   Вверх
Experimenter
Дата 8.2.2011, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, добавьте в конструктор еще одну строку:
Код

            pictureBox1.Image = bmSector;

и увидите, что у вас в битмапе


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
Georgich
Дата 8.2.2011, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Experimenter, сделал так, закомментил эту же строку в Timer_Tick. При загрузке формы весь pictureBox прозрачный. Нажимаю на кнопку - черный фон. Не могу сейчас осознать до конца этот момент.
PM MAIL   Вверх
Experimenter
Дата 8.2.2011, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, сравните два конструктора битмапа:
Код

    new Bitmap(pictureBox1.Width, pictureBox1.Height, PixelFormat.Format32bppArgb);
и
Код

    new Bitmap(pictureBox1.Width, pictureBox1.Height, PixelFormat.Format24bppRgb);

В вашем коде в конструкторе формы неявно вызывается именно первый, можете рефлектором посмотреть. Отсюда и прозрачный фон.


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
Georgich
Дата 8.2.2011, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 20.1.2008

Репутация: нет
Всего: нет



Experimenter, спасибо за разъяснение про "закулисие".
Так, собственно, а как от черного фона-то избавится при формате в 24 бита? Вот это мне не ясно.
PM MAIL   Вверх
Experimenter
Дата 8.2.2011, 14:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 430
Регистрация: 8.5.2007
Где: Уфа

Репутация: 8
Всего: 17



Georgich, ну, например, создать изображение с фоном формы.
Код

        public Form1()
        {
            InitializeComponent();
            drawSector = new DrawPicture(ref pictureBox1);//(pictureBox1.Width, pictureBox1.Height);
            bmSector = CreateBitmap();
        pictureBox1.Image = bmSector;
        }

        private Bitmap CreateBitmap()
        {
            Bitmap b = new Bitmap(
                pictureBox1.Width, pictureBox1.Height, PixelFormat.Format24bppRgb);
            using (Graphics g = Graphics.FromImage(b))
            {
                g.Clear(this.BackColor);
                g.DrawImage(b, 0.0f, 0.0f);
            }
            return b;
        }


Это сообщение отредактировал(а) Experimenter - 8.2.2011, 14:10


--------------------
public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){
    if(zlo1 < zlo2) return zlo1;
    else if(zlo1 > zlo2) return zlo2;
    else throw new Exception("Kill yourself by the wall"); }
PM WWW ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1054 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.