Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/15: Рейтинг темы: голосов - 15, средняя оценка - 4.73
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
1

Gdiplus::Bitmap - получить указатель на растровые данные в правильном порядке

20.06.2014, 10:55. Показов 3132. Ответов 16
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет!

Есть код работы с Gdiplus::Bitmap:

C++
1
2
3
4
5
6
7
8
9
10
unsigned int SizeCol,SizeRow;
 
SizeCol = this->OriginalBitMap->GetWidth();
SizeRow = this->OriginalBitMap->GetHeight();
Gdiplus::Rect mRect(0,0,SizeCol,SizeRow);
Gdiplus::BitmapData bd;
 
CurrentBitMap->LockBits(&mRect,Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite,this->CurrentBitMap->GetPixelFormat(),&bd);
WholeCurrRastData = (BYTE*)bd.Scan0;
this->CurrentBitMap->UnlockBits(&bd);
где CurrentBitMap - Gdiplus::Bitmap, заранее заданный
WholeCurrRastData - char*. В него я пытаюсь получить указатель на растровые данные, чтобы потом с ним отдельно поработать. Так вот, проблема в том, что указатель ссылается на данные но всегда в разном порядке, в зависимости от Gdiplus::BitmapData::Stride. Что означает Stride, выдержка из MSDN:
Шаг по индексу — это ширина ряда пикселей (строки развертки), округленного до четырех байтов. Если шаг по индексу положителен, точечный рисунок является нисходящим. Если шаг по индексу отрицательный, точечный рисунок является восходящим.

Как с учетом этого преобразовать указатель, чтобы данные всегда были по порядку от верхней строки, первого элемента до последней строки последнего элемента - я не знаю. Помогите, плиз.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.06.2014, 10:55
Ответы с готовыми решениями:

Деструктор Gdiplus::bitmap
Пример совсем простенький, создаем bitmap в GDI+, но при завершении работы программы выскакивает...

Получить данные через указатель из dll на delphi
Здравствуйте, помогите пожалуйста! имеется dll, написанная на delphi, где есть процедура: ...

Как получить ссылку на указатель или указатель на указатель в массиве?
В процессе реализации сортировки пузырьком натолкнулся на такую проблему: как поменять значения...

C выводит инфу не в правильном порядке
Недавно перешел на СИ (пишу в Eclipse) и сразу столкнулся с такой проблемой. Вроде бы пишу в...

16
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
20.06.2014, 11:04 2
Stride - ширина растра в байтах с учетом выравнивания.

C++
1
2
for(int row=0;row<height;row++)
    BYTE* RowData = WholeCurrRastData+row*bd.Stride;
1
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
20.06.2014, 11:35  [ТС] 3
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
C++
1
2
for(int row=0;row<height;row++)
* * BYTE* RowData = WholeCurrRastData+row*bd.Stride;
Здесь вы в RowData выгружаете по одной строке данных, начиная с какой, не понял?
Мне же нужно весь указатель WholeCurrRastData перетасовать так, чтобы вне зависимости от Stride данные в нем были так, как они видятся на Gdiplus::Bitmap сверху вниз.

Добавлено через 3 минуты
Коллега, который до меня работал с этим кодом, написал так (с учетом того в используемом Gdiplus::Bitmap, PixelFormat = pf8bit):

C++
1
2
3
4
5
if (bd.Stride < 0)
{
    this->WholeCurrRastData += (-(bd.Stride));
    this->WholeCurrRastData -= (std::abs(bd.Stride) * SizeRow);
}
Но в этом случае данные представляются отраженными сверху вниз. А мне надо наоборот
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
20.06.2014, 12:07 4
Цитата Сообщение от doomkin Посмотреть сообщение
Здесь вы в RowData выгружаете по одной строке данных, начиная с какой, не понял?
Я не выгружаю, я считаю адрес начала строки относительно начала растра. Ширина строки в байтах - Stride, растр может быть top-down или bottom-up. Определяется по знаку Stride. Если есть работающий код, разверните условие, в чем проблема-то?

Добавлено через 15 минут
UP.
Наверное понял. bd.Scan0 - начало растра в памяти. Растр лежит строками, шириной Stride байт. Логическое начало координат определяется по знаку Stride.

При положительном Stride - начало строки считается row_no*Stride
При отрицательном Stride - начало строки считается (image_height - row_no -1)*abs(Stride)
1
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
20.06.2014, 14:29  [ТС] 5
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
При положительном Stride - начало строки считается row_no*Stride
При отрицательном Stride - начало строки считается (image_height - row_no -1)*abs(Stride)
Не все работает. Я сделал так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
BYTE* RowData;
byte b;
 
 
            if(pParam->Stride < 0)
            {
                for(int row = 1;row < pParam->Rows + 1; row++)
                {
                    RowData = Dest + ((pParam->Rows - row - 1) - 1) * abs(pParam->Stride);
                    for(int col = 1;col < pParam->Cols + 1; col++)
                    {
                        b = lutDest[Sourse[row * col - 1]];
                        RowData[col - 1] = b;
                    }
                }
            }
            else
            {
                for(int row = 1;row < pParam->Rows + 1; row++)
                {
                    RowData = Dest + (row - 1) * pParam->Stride;
                    for(int col = 1;col < pParam->Cols + 1; col++)
                    {
                        b = lutDest[Sourse[row * col - 1]];
                        RowData[col - 1] = b;
                    }
                }
            }
Dest - указатель Scan0
Source - 16 битные значения, которые соответствуют картинке Gdiplus::Bitmap из которой взят указатель на Dest. В Source все значения хранятся от первого к последнему в прямом порядке.
lutDest - таблица 8 - битных значений, которые соответствуют 16 - битному элементу.

Если Stride положительный, - срабатывает без исключений и то не всегда, но отображает тарабарщину.
Если отрицательный вроде правильно все показывает, но в определенный момент кричит, что

First chance exception at $0045455F. Exception class $C0000005 with message 'access violation at 0x0045455f: write of address 0x3328d020'. Process AAA.exe (11524)
Может это потому, что я указатель буторю в потоке, а перед созданием потока уже вызываю функцию UnlockBits. Т.е. получил указатель и UnlockBits, а только потом его обрабатываю. При этом, если то же самое делаю без всех этих сложных скачков по памяти, - то все норм работает, но только, если Stride положительный. Если отрицательный - тоже работает, но изображение отраженное сверху вниз.
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
20.06.2014, 14:56 6
Цитата Сообщение от doomkin Посмотреть сообщение
Т.е. получил указатель и UnlockBits, а только потом его обрабатываю.
Нельзя так. LockBits создает временный буфер и возвращает указатель на него. UnlockBits его освобождает.
Не совсем понял - какой именно формат пикселя у изображения?
0
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
20.06.2014, 15:03  [ТС] 7
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
Нельзя так. LockBits создает временный буфер и возвращает указатель на него. UnlockBits его освобождает.

Так все прекрасно работает .
C++
1
2
3
4
5
for (int i = 0; i < pParam->Cols * pParam->Rows; i++)
{
  b = lutDest[Sourse[i]];
  Dest[i] = b;
}

Я бы с радостью передавал в поток через параметры указатель на свой Bitmap и оттуда бы получал Scan0. Но изнутри потока почему-то он Scan0 выдает NULL.
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
20.06.2014, 15:08 8
Цитата Сообщение от doomkin Посмотреть сообщение
Так все прекрасно работает
Ну это просто везет пока, буфер еще не потерся. Поток-то зачем?
0
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
20.06.2014, 15:30  [ТС] 9
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
Ну это просто везет пока, буфер еще не потерся. Поток-то зачем?
В потоке необходимо пересчитать значения яркости/контрастности по 16-битным значениям и потом по таблице обновить значения в растре. Изображение 9 Мп, а операция привязана к мыши, поэтому в потоке.
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
20.06.2014, 15:36 10
Для индексированных серых изображений при регулировке Я/К пересчитывается не яркость каждой точки, а палитра. Само изображение пересчитывается один раз, при сохранении, когда в диалоге Ok нажали.
0
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
20.06.2014, 15:44  [ТС] 11
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
Для индексированных серых изображений при регулировке Я/К пересчитывается не яркость каждой точки, а палитра. Само изображение пересчитывается один раз, при сохранении, когда в диалоге Ok нажали.
Примерчик в студию

Добавлено через 2 минуты
Вот так палитру создаем:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
LOGPALETTE* plLogPal;
plLogPal = NULL;
         int ilPaletteSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 255);
         plLogPal = (LOGPALETTE*) malloc(ilPaletteSize);
 
         plLogPal->palVersion = 0x300;
         plLogPal->palNumEntries = 256;
         for (int ilColorIndex = 0; ilColorIndex <= 255; ilColorIndex++)
         {
             plLogPal->palPalEntry[ilColorIndex].peRed = ilColorIndex;
             plLogPal->palPalEntry[ilColorIndex].peGreen = ilColorIndex;
             plLogPal->palPalEntry[ilColorIndex].peBlue = ilColorIndex;
             plLogPal->palPalEntry[ilColorIndex].peFlags = PC_NOCOLLAPSE;
         }
 
HPALETTE hLogPal;
hLogPal = CreatePalette(plLogPal);
BMP->Palette = CreatePalette(plLogPal);
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
20.06.2014, 16:05 12
Цитата Сообщение от doomkin Посмотреть сообщение
Примерчик в студию
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
      if(palette_)
      {
         free(palette_);
         palette_ = 0;
      }
      palette_ = (Gdiplus::ColorPalette*)malloc(sizeof(Gdiplus::ColorPalette) + 256 * sizeof(Gdiplus::ARGB));
      palette_->Flags = Gdiplus::PaletteFlagsGrayScale;
      palette_->Count = 256;
      for(int i=0;i<256;i++)
      {
         palette_->Entries[i] = Gdiplus::Color::MakeARGB(255, lut[i], lut[i], lut[i]);
      }
      image_->SetPalette(palette_);
1
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
23.06.2014, 11:49  [ТС] 13
Спасибо за пример. Так работает, только нужно так использовать:
C++
1
lut[i*64]
потому что lut - 14-битная таблица.

НО. Теперь, вне зависимости в каком порядке я ввожу значения в палитру: с 0 до 255 в позитиве, или с 255 до 0 в негативе, картинка, почему-то хоть так, хоть так, отображается в негативе. В чем дело?
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
23.06.2014, 11:57 14
Цитата Сообщение от doomkin Посмотреть сообщение
только нужно так использовать:
C++
1
lut[i*64]
Уверены? а не увеличить количество входов палитры до 2^14 ?
Иначе - каким цветом должны отображаться точки с уровнем не кратным 64?
0
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
23.06.2014, 12:05  [ТС] 15
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
Уверены? а не увеличить количество входов палитры до 2^14 ?
Иначе - каким цветом должны отображаться точки с уровнем не кратным 64?
На мониторе больше 255 оттенков все равно не покажешь. Не совсем понимаю, что даст увеличение размера палитры. С этим особых проблем нет. Проблема с негативом/позитивом
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
23.06.2014, 12:21 16
Цитата Сообщение от doomkin Посмотреть сообщение
Не совсем понимаю, что даст увеличение размера палитры.
Ну мне отсюда задачу не видно, проблема с негативом - позитивом однозначно кривая палитра. Сохранить один и тот же растр в файл с дефолтной и поправленой палитрой, и сравнить в стороннем приложении.

Добавлено через 10 минут
UP.
Кстати да - там случаем при присвоении из lut байт не переполняется?
0
2 / 5 / 1
Регистрация: 14.05.2013
Сообщений: 99
27.06.2014, 16:57  [ТС] 17
В негативе так надо формировать палитру, чтобы все нормально отображалось:
C++
1
2
3
4
for(int i=0;i<256;i++)
{
  palette_->Entries[i] = Gdiplus::Color::MakeARGB(255, lutDest[(255 - i)*64], lutDest[(255 - i)*64], lutDest[(255 - i)*64]);
}
0
27.06.2014, 16:57
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.06.2014, 16:57
Помогаю со студенческими работами здесь

Вывод записей из таблицы в правильном порядке
Здраствуйте люди. Скажите как мне сделать такую вещь... На 1 скриншоте - моя таблица для...

Разнести информацию по столбцам в правильном порядке
Добрый вечер. Можно ли как-то раскидать информацию в таблице по столбцам в правильном порядке...

Расставьте строки программы в правильном порядке
Расставь строки программы в правильном порядке, чтобы получилась программа, которая находит решение...

Расставьте строки программы в правильном порядке
Расставьте строки программы в правильном порядке, чтобы получилась программа, которая находит сумму...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru