DirecTwiX 4 Жалоба Опубликовано September 24, 2011 Неделю назад написал такую функцию: void Bmp2Mat(HDC hDC, HBITMAP hBmp, cv::Mat &img8UC3) { int size=3*img8UC3.cols*img8UC3.rows; BYTE *bmpData = new BYTE[size]; BITMAPINFOHEADER bmi={0}; bmi.biSize = sizeof(BITMAPINFOHEADER); bmi.biPlanes = 1; bmi.biBitCount = 24; bmi.biWidth = img8UC3.cols; bmi.biHeight = -img8UC3.rows; bmi.biCompression = BI_RGB; GetDIBits(hDC, hBmp, 0, img8UC3.rows, bmpData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); memcpy(img8UC3.data, bmpData, size); delete [] bmpData; } Вытаскивал матрицу из HDC... Работала (да и до сих пор работает) без пререканий, но только на одном окне (мне в принципе другие не нужны, но разобраться хочется). Сегодня решил потестить для окна калькулятора... И что я увидел? Ошибку "Heap corruption detected"... Оказалось, что GetDIBits каким-то образом пишет за пределы массива... Гуглил-гуглил и вот что нашёл: http://www.rsdn.ru/forum/winapi/111983.flat.aspx Там похожая проблема, но только для 4 бит (сказали, что функа ещё палитру пытается всунуть). Мне добавить в bmi массив размера 2^24???? На msdn вроде написано, что палитру не должно записывать =\ Да и почему для одного окна работает, а для другого сыпется? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано September 25, 2011 1. А почему высоту ты со знаком "-" записываешь? 2. В твоём случае значения, скорее всего, не имеет, но размер изображения не всегда равен 3*img8UC3.cols*img8UC3.rows. Если cols (вдруг!) будет нечётным, то можешь получить затирание памяти. Обычно строки в памяти выравниваются по 4 байта. 3. Почему бы не добавить палитру, как сказал Alex Fedotov? Там же совсем не 2^24 байт. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DirecTwiX 4 Жалоба Опубликовано September 25, 2011 1. Иначе изображение будет перевёрнутым 2. Какие строки имеются в виду? GetDIBits и Img.data - это один длинный участок в памяти 3. А сколько? 24 бита на цвет -> всего 2^24 возможный цветов Проблема решена. Оказалось, что везде работает, кроме калькулятора (win7). У него с шириной какая-то бага. По факту она 1 пиксель больше чем выдаёт GetWindowRect/GetClientRect =) Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано September 25, 2011 Выравнивание это. Каждая строка для 32 битного режима должна быть выравнена на границе 4 байт. А так как пиксель 3 байта, то при нечётной длине строки имеем неправильный размер. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано September 25, 2011 2. Какие строки имеются в виду? GetDIBits и Img.data - это один длинный участок в памяти Любые. Pavia00 прав. Длина строки выровнена на 4 байта, это надо учитывать. Именно для этого в структуре IplImage есть значение widthStep. Можешь, кстати, провести эксперимент. Создай в Паинте два 24 битных bmp одинаковой высоты 12 пикселей, но разной ширины: один 11 пикселей, а другой 12. И сравни размеры получившихся файлов - они будут одинаковыми. Так же ведут себя поверхности и текстуры, хотя они иногда вообще до ближайшей сверху степени двойки выравниваются. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DirecTwiX 4 Жалоба Опубликовано September 25, 2011 Ладно... Уговорили) У калькулятора ширина и в правду нечётной была =\ Сколько тогда памяти выделять? Вот немного переписал: void Bmp2Mat(HDC hDC, HBITMAP hBmp, cv::Mat &img) { BITMAPINFOHEADER bmi={0}; bmi.biSize = sizeof(BITMAPINFOHEADER); GetDIBits(hDC, hBmp, 0, 0, 0, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); bmi.biPlanes=1; bmi.biBitCount = 24; bmi.biCompression = BI_RGB; int size=3*bmi.biHeight*bmi.biWidth; bmi.biHeight=-bmi.biHeight; BYTE *bmpData = new BYTE[size]; GetDIBits(hDC, hBmp, 0, -bmi.biHeight, bmpData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); img=cv::Mat(-bmi.biHeight, bmi.biWidth, CV_8UC3); memcpy(img.data, bmpData, size); delete [] bmpData; } UPD: если перед int size=... добавить if (bmi.biWidth%4) bmi.biWidth=4-bmi.biWidth%4+bmi.biWidth; То всё будет работать... Но если ширина изображения не кратна 4, то справа появляются лишние столбы (от 1 до 3). Пробовал уменьшать размер матрицы - безрезультатно. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано September 25, 2011 Всё правильно делаешь. Я не работал с cv::Mat, а всё больше с IplImage. Там всё решается с помощью widthStep Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах