C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с пикселями bmp изображения  (Прочитано 17078 раз)
dan1234567
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 8


« : 05 Февраль 2012, 14:51:03 »

Помогите пожалуйста  нужно открыть bmp изображение попиксельно,  а потом изменить размер задавать ширину и высоту вручную. Прочитал про bmp c википедии, нашел на Delphi но мне нужно на C++ builder. Зарание спасибо!
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #1 : 05 Февраль 2012, 15:16:16 »

Код:
Graphics::TBitmap* Bmp=new Graphics::TBitmap;
AnsiString FileName;
 if (OpenPictureDialog1->Execute())
  { FileName=OpenPictureDialog1->FileName;
  };
  if(FileName=="")return;
Bmp->LoadFromFile(FileName);

if(Bmp->PixelFormat==pf24bit)  // only 24bit
{Byte R,G,B;
int x,y;
{for(y=0; yHeight; y++)
  { ptr=(Byte*)Bmp->ScanLine[y];
    for(x=0; xWidth; x++)
    { B=ptr[x*3]; G=ptr[x*3+1]; R=ptr[x3+2]);
}
}
}
}
delete Bmp;
Вроде так (не компилил) вы получите попиксельный доступ. Для масштабирования надо создать второй бмп и копировать из первого во второй.
« Последнее редактирование: 05 Февраль 2012, 23:48:00 от gumi250 » Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


« Ответ #2 : 05 Февраль 2012, 19:30:14 »

Помогите пожалуйста  нужно открыть bmp изображение попиксельно,  а потом изменить размер задавать ширину и высоту вручную. Прочитал про bmp c википедии, нашел на Delphi но мне нужно на C++ builder. Зарание спасибо!

Это такие условия задачи или сам решил?
Чего же проще на один битмап загрузить картинку, а на вторую копирить stretchdraw
Записан
dan1234567
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 8


« Ответ #3 : 06 Февраль 2012, 01:44:56 »

Да  такие условия, потому и тяжело изменить размер изображения
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


« Ответ #4 : 06 Февраль 2012, 10:36:20 »

Да  такие условия, потому и тяжело изменить размер изображения

Код
 int WidthSource, HeightSource;        // исходные размеры
int WidthDest, HeightDest; // конечные размеры
 
Graphics::TBitmap *sour = new Graphics::TBitmap();
Graphics::TBitmap *dest = new Graphics::TBitmap();
 
sour->LoadFromFile("pict.bmp");
 
WidthSource = sour->Width;
HeightSource = sour->Height;
 
WidthDest = Image1->Width;
HeightDest = Image1->Height;
dest->Width = WidthDest;
dest->Height = HeightDest;
 
float kX = (float)WidthDest / (float)WidthSource;
float kY = (float)HeightDest / (float)HeightSource;
 
for (int x = 0; x < WidthSource; x++)
for (int y = 0; y < HeightSource; y++)
{
for (int i = 0; i < kX; i++)
for (int j = 0; j < kY; j++)
{
dest->Canvas->Pixels[x*kX+i][y*kY+j] = sour->Canvas->Pixels[x][y];
}
}
 
Image1->Canvas->Draw(0,0, dest);
 
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


« Ответ #5 : 06 Февраль 2012, 10:40:07 »

Но это без передискретизации. Т.е. искажения всякие. Для более красивого масштабирования нужна интерполяция. Тут уж миллион вариантов. Статей в инете еще больше.
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #6 : 06 Февраль 2012, 11:34:02 »

POV я бы дал вам приз за самый медленный способ масштабирования изображения . Будет ооооочень медленно (из-за Pixels[][] ). Нужно хотя бы ScanLine использовать. А лучше что-нибудь готовое вроде stretchdraw или StretchBlt
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


« Ответ #7 : 06 Февраль 2012, 11:35:36 »

Сказал же топикстартер что ему попиксельно надо. Что попросил, то и получил )
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #8 : 06 Февраль 2012, 11:44:07 »

Ну ScanLine вообщем то тоже попиксельно, но на порядок быстрее.
Записан
Leex
Участник


Сказали спасибо: +132/-1
Offline

Сообщений: 577


« Ответ #9 : 06 Февраль 2012, 12:03:17 »

Цитировать
Будет ооооочень медленно (из-за Pixels[][] ). Нужно хотя бы ScanLine использовать.
Что тот тормозной, что другой. Если нужна скорость, то это в сторону CreateDIBSection и далее прямая работа с памятью, скорость будет выше на несколько порядков
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #10 : 06 Февраль 2012, 12:20:31 »

То что использование ScanLine вместо Pixels[][] при полной обработке картинки ускорит процесс на порядок это точно. Но тошто использование DIB вместо ScanLine хоть как то ускорит процесс (ваше утверждение про на несколько порядков будем считать преувеличением) я сомневаюсь . Давайте сравним. К сожалению никогда не использовал DIB для попиксельного доступа, если вам не трудно, приведите простенький пример как с помощью DIB, скажем в bmp картинке (24 bit) яркость каждого пикселя увеличить на 1. Я напишу тоже самое со ScanLine и Pixels[][] и сравню.
« Последнее редактирование: 06 Февраль 2012, 15:25:22 от gumi250 » Записан
dan1234567
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 8


« Ответ #11 : 06 Февраль 2012, 17:11:20 »

Я читаю пиксели так:
// Read the data for a 24-bit image.

    // Number of bytes used to store each pixel row in the
    // the file. This value is rounded up to the nearest
    // multiple of four.
    unsigned int physicalrowsize = (3 * width + 0x3) & ~0x3 ;
    // Size of the padding for each row.
    unsigned int padsize = physicalrowsize -  3 * width ;

    // Images with positive heights are stored bottom up. Images with
    // negative height are stored top down.
    if (height > 0)
    {
      for (unsigned int yy = 0 ; yy < height ; ++ yy)
      {
        CallProgressFunction (yy * 100 / height) ;

        unsigned int index = height - yy - 1 ;
        // Have to read the sample values separately because the colors
        // are in reverse order: BGR. If you are on Windows you could
        // red the whole thing a row at a time.
        for (unsigned int xx = 0 ; xx < 3 * width ; xx += 3)
        {
          strm.read ((char *)&image[index][xx + BitmapImage::BlueOffset], 1) ;
          strm.read ((char *)&image[index][xx + BitmapImage::GreenOffset], 1) ;
          strm.read ((char *)&image[index][xx + BitmapImage::RedOffset], 1) ;
        }
        static char pad [4] ;
        strm.read (pad, padsize) ;
      }
    }
    else
    {
      for (unsigned int yy = 0 ; yy < -height ; ++ yy)
      {
        CallProgressFunction (yy * 100 / -height) ;

        // Have to read the sample values separately because the colors
        // are in reverse order: BGR. If you are on Windows you could
        // red the whole thing a row at a time.
        for (unsigned int xx = 0 ; xx < 3 * width ; xx += 3)
        {
          strm.read ((char *)&image[ii][xx + BitmapImage::BlueOffset], 1) ;
          strm.read ((char *)&image[ii][xx + BitmapImage::GreenOffset], 1) ;
          strm.read ((char *)&image[ii][xx + BitmapImage::RedOffset], 1) ;
        }
        static char pad [4] ;
        strm.read (pad, padsize) ;
      }
    }
  }
  CallProgressFunction (100) ;
  return ;
}
--------------------------------------
но как изменять ширину и высоту не знаю?
Записан
Rius
Давний друг


Сказали спасибо: +116/-5
Offline

Сообщений: 753


« Ответ #12 : 06 Февраль 2012, 18:36:23 »

Цитировать
но как изменять ширину и высоту не знаю?
Создаёте новый bmp нужных размеров и на нём рисуете старый bmp.
Записан
Leex
Участник


Сказали спасибо: +132/-1
Offline

Сообщений: 577


« Ответ #13 : 07 Февраль 2012, 01:43:11 »

Цитировать
Давайте сравним. К сожалению никогда не использовал DIB для попиксельного доступа, если вам не трудно, приведите простенький пример как с помощью DIB, скажем в bmp картинке (24 bit) яркость каждого пикселя увеличить на 1. Я напишу тоже самое со ScanLine и Pixels[][] и сравню.
не вопрос, мой проект в аттаче.

в релизе, под виртуалкой мой старенький проц (C2D e7200 2.5ггц) стабильно хавает бмпешку размером 1920х1200@24 за 10 мс. Так медленно вероятно из-за виртуалки

Дело за вами gumi250  
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #14 : 07 Февраль 2012, 04:05:15 »

To Leex:
Переделал ваше приложение из консольного в оконное (не люблю консоль). Добавил своих ф-ций. Результат прилагаю.
Взял картинку размером 3840x2268@24, на старом компе.
Типичный результат многих запусков:
time of DIB processing: 344ms
time of ScanLine processing: 219ms
time of PIX processing: 21828ms
complete
Признаюсь результат меня сильно удивил (думал, что DIB быстрее). Может чего не так сделал.
« Последнее редактирование: 07 Февраль 2012, 05:11:17 от gumi250 » Записан
Leex
Участник


Сказали спасибо: +132/-1
Offline

Сообщений: 577


« Ответ #15 : 07 Февраль 2012, 11:56:32 »

Во-первых проверять скорость нужно в релизе, а во-вторых мой код не оптимален, там есть ненужный итератор.
нужно заменить
Код
int i=pbih->biSizeImage;          /////
while(i--)                        /////цикл обработки пикселей
 *tbuf+++=10;                    /////
на
Код
char* stopbuf=tbuf+pbih->biSizeImage;
while(tbuf!=stopbuf)                      
*tbuf+++=10;/////цикл обработки пикселей

а вот что говорит дизасемблер в релизе:
 мой код
Код
Unit1.cpp.111: char* stopbuf=tbuf+pbih->biSizeImage;
00402091 03D0             add edx,eax
Unit1.cpp.112: while(tbuf!=stopbuf)                        /////цикл обработки пикселей
00402093 3BD0             cmp edx,eax
00402095 7408             jz $0040209f
Unit1.cpp.113: *tbuf+++=10;                    /////
00402097 80000A           add byte ptr [eax],$0a
0040209A 40               inc eax
Unit1.cpp.112: while(tbuf!=stopbuf)                        /////цикл обработки пикселей
0040209B 3BD0             cmp edx,eax
0040209D 75F8             jnz $00402097

твой код
Код
Unit1.cpp.54: for(y=0; y
00401E68 33F6             xor esi,esi
00401E6A 3B75C8           cmp esi,[ebp-$38]
00401E6D 7D2F             jnl $00401e9e
Unit1.cpp.55: { ptr=(Byte*)Bmp1->ScanLine[y];
00401E6F 8B4508           mov eax,[ebp+$08]
00401E72 8BD6             mov edx,esi
00401E74 8B8080030000     mov eax,[eax+$00000380]
00401E7A E809220000       call $00404088
Unit1.cpp.56: for(x=0; x
00401E7F 33D2             xor edx,edx
00401E81 3BDA             cmp ebx,edx
00401E83 7E13             jle $00401e98
Unit1.cpp.57: { ptr[x++]+=10; //B
00401E85 80000A           add byte ptr [eax],$0a
00401E88 40               inc eax
00401E89 42               inc edx
Unit1.cpp.58: ptr[x++]+=10; //G
00401E8A 42               inc edx
00401E8B 80000A           add byte ptr [eax],$0a
00401E8E 40               inc eax
Unit1.cpp.59: ptr[x++]+=10; //R
00401E8F 42               inc edx
00401E90 80000A           add byte ptr [eax],$0a
00401E93 40               inc eax
00401E94 3BDA             cmp ebx,edx
00401E96 7FED             jnle $00401e85
00401E98 46               inc esi
00401E99 3B75C8           cmp esi,[ebp-$38]
00401E9C 7CD1             jl $00401e6f
минус твоего кода - это вызов вункции ScanLine.
минус моего - то что проверка tbuf!=stopbuf выполняется после изменения каждого байта, хотя мне же не кто не запрещает написать как у тебя:
Код
while(tbuf!=stopbuf)
{                      
*tbuf+++=10;
*tbuf+++=10;
*tbuf+++=10;
}
Думаю очевидно какой способ быстрее, хотя на самом деле разница очень несущественна, т.к идет прямая работа с памятью, и применяемый способ измерения производительности здесь не подходит
вроде всё наглядно получилось
На счет того, что работа с диб напрямую существенно быстрее ScanLine, я погорячился  
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #16 : 07 Февраль 2012, 13:07:22 »

Цитировать
Во-первых проверять скорость нужно в релизе
Конечно, это я просто отвык в релизе компилить .

На сколько я понимаю DIB формат хранит картинку непрерывным куском памяти, а TBmp хранит каждую строку в отдельном участке памяти. Поэтому у DIB есть один указатель на начала массива пикселей, а у бмп нужно получать указатель для начала каждой строки пикселей (это делает ScanLine). При каждом обращении к Pixel[][] он "вызывает ScanLine", поэтому при массовом использовании Pixel[][] наблюдаются жуткие тормоза.

Плюс DIB возникает только тогда когда можно обращаться к пикселям как к одномерному массиву (когда координаты пикселя не нужны) вроде Data[], также можно быстро копировать целым куском памяти из одного места в другое. К пикселям же бмп всегда надо обращаться как двумерному массиву, вроде Data[][] (очевидно, что это медленее чем одномерный Data[]), также при копировании надо копировать память кусками размером в строку. В этих случаях DIB должен быть быстрее Bmp.
Но при "сложных" алгоритмах когда нужно именно рассматривать картинку как двумерный массив (когда для вычисления значение пикселя нужно знать его координаты x и y), в обоих случаях используется двумерный массив вида  Data[][], и тогда абсолютно одинаково, что DIB, что Bmp->ScanLine (но только не Bmp->Pixel[][]).
Зато код Bmp->ScanLine проще, короче, понятнее чем DIB.

P.S. А что означает +++=, чем он отличается от += ?

« Последнее редактирование: 07 Февраль 2012, 13:13:20 от gumi250 » Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #17 : 07 Февраль 2012, 13:39:13 »

Цитировать
А что означает +++=, чем он отличается от += ?
А увеличивать значение указателя кто будет? Фактически - это (*(tbuf++))+=10; (поскольку приоритеты * и ++ одинаковы, а ассоциативность - справа налево, то я поставил внутренние скобки именно для tbuf++)
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #18 : 07 Февраль 2012, 14:16:33 »

Ух ты не сообразил что +++= это ++ и +=
Записан
dan1234567
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 8


« Ответ #19 : 07 Февраль 2012, 15:59:08 »

To Leex:
Переделал ваше приложение из консольного в оконное (не люблю консоль). Добавил своих ф-ций. Результат прилагаю.
Взял картинку размером 3840x2268@24, на старом компе.
Типичный результат многих запусков:
time of DIB processing: 344ms
time of ScanLine processing: 219ms
time of PIX processing: 21828ms
complete
Признаюсь результат меня сильно удивил (думал, что DIB быстрее). Может чего не так сделал.

Пробовал Вашу программу но там нет файла проекта, я использую С++ builder 2005, или я неправильно что то делаю?
Записан
gumi250
Участник


Сказали спасибо: +33/-1
Offline

Сообщений: 254


« Ответ #20 : 07 Февраль 2012, 17:45:45 »

Цитировать
Пробовал Вашу программу но там нет файла проекта, я использую С++ builder 2005, или я неправильно что то делаю?
проверил есть Project3.cbproj. У меня C++Builder XE, наверно поэтому так. Создайте свой проект из моих cpp файлов
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.141 секунд. Запросов: 23.