Перейти к содержимому
Compvision.ru
blackfxx

HBITMAP to IplImage*

Recommended Posts

Необходима функция для перевода HBITMAP to IplImage*. А то в данный момент я делаю скриншот экрана, получаю его в HBITMAP'e и сохраняю на диск а потом гружу cvLoadImage. Вприницпе не очень устраивает. Хотелось сразу в IplImage.

смотрел топик http://www.compvision.ru/forum/index.php?showtopic=280

Сам тоже находил в инете вот эту функцию.

IplImage* hBitmap2Ipl(HBITMAP hBmp)

{

BITMAP bmp;

::GetObject(hBmp,sizeof(BITMAP),&bmp);

int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel/8 ;

int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;

IplImage* img = cvCreateImageHeader( cvSize(bmp.bmWidth, bmp.bmHeight)

, depth, nChannels );

img->imageData =

(char*)malloc(bmp.bmHeight*bmp.bmWidth*nChannels*sizeof(char));

memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels);

return img;

}

Но она прерывается на строчке

memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels);

Unhandled exception at 0x576fbe20 (msvcr100d.dll) in testApp.exe: 0xC0000005: Access violation reading location 0x00000000.

Может кто сталкивался? или есть идеи что изменить?

UPD> проблему решил. Это оказался только кусок процедуры. Пришлось хорошо поломать голову.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IplImage * GetIplImage(HBITMAP HBM)

{

	BITMAP BM;  	 

	LPBITMAPINFO BIP;  

	HDC DC;      

	DWORD DataSize;   

	WORD BitCount;   	


	GetObject(HBM, sizeof(BITMAP), (LPSTR)&BM);


	BitCount = (WORD)BM.bmPlanes * BM.bmBitsPixel;

	DataSize = ((BM.bmWidth*BitCount+31) & ~31)/8*BM.bmHeight;


	BIP=(LPBITMAPINFO)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(BITMAPINFOHEADER));

	BIP->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

	BIP->bmiHeader.biWidth = BM.bmWidth;

	BIP->bmiHeader.biHeight = BM.bmHeight;

	BIP->bmiHeader.biPlanes = 1;

	BIP->bmiHeader.biBitCount = BitCount;

	BIP->bmiHeader.biCompression = 0;

	BIP->bmiHeader.biSizeImage = DataSize;

	BIP->bmiHeader.biXPelsPerMeter = 0;

	BIP->bmiHeader.biYPelsPerMeter = 0;

	if (BitCount < 16) 

		BIP->bmiHeader.biClrUsed = (1<<BitCount);

	BIP->bmiHeader.biClrImportant = 0;


	DC = GetDC(0); 


	BYTE * bits;			// массив для битов изображения

	long imgsize, pixels;	// Различные размерности для записи файла 		


	pixels = BIP->bmiHeader.biWidth	* BIP->bmiHeader.biHeight; 


	switch(BIP->bmiHeader.biBitCount) 

	{ 

	case 4:

		imgsize = pixels / 2;

		break; 

	case 8:

		imgsize	= pixels;

		break; 

	case 16:

		imgsize	= pixels * 2;

		break; 

	case 24:

		imgsize	= pixels * 3;

		break; 

	case 32:

		imgsize = pixels * 4;

		break; 

	default:

		break;

	}


	//	выделяем память под биты изображения

	bits = (unsigned char*)GlobalAlloc(GMEM_FIXED,imgsize); 


	//Заполняем массив битов изображения 

	int i = GetDIBits( DC, // дескриптор контекста устройства 

		HBM, // дескриптор изображения 

		0, // первая выбираемая линия для изображения назначения 

		BIP->bmiHeader.biHeight, // количество выбираемых линий 

		bits, // адрес массива битов изображения 

		(BITMAPINFO*)&BIP->bmiHeader,// адрес структуры с данными изображения 

		DIB_RGB_COLORS // RGB или индекс палитры 

		); 	


	//	заполняем данные по изображению

	int nChannels = BM.bmBitsPixel == 1 ? 1 : BM.bmBitsPixel/8 ;

	int depth = BM.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;

	IplImage* img = cvCreateImageHeader(cvSize(BM.bmWidth, BM.bmHeight), depth, nChannels);


	//	выделяем память под биты

  	img->imageData = (char*) malloc( BM.bmHeight * BM.bmWidth* nChannels * sizeof(char));		


  	//	копируем биты 

	memcpy( img->imageData, (char*)(bits), BM.bmHeight * BM.bmWidth * nChannels);


    //	изображение получается перевернутым	

	IplImage * imgModified = cvCreateImage(cvSize(img->width,img->height),img->depth, 3);

	cvCvtColor(img, imgModified, CV_BGRA2BGR); //	в img используеются 4 канала, мне необходимо только три

	IplImage * imgMirror = cvCreateImage(cvSize(img->width,img->height),img->depth, 3);

  	cvMirror(imgModified, imgMirror);	//	приводим в нормальный вид


  	//	убираем мусор

	cvReleaseImage(&imgModified);

 	free( img->imageData); 	

	cvReleaseImage(&img);	

	ReleaseDC(0, DC);		

	GlobalFree((HGLOBAL)bits);	

	HeapFree(GetProcessHeap(),0,(LPVOID)BIP); 		

	return	(imgMirror);		

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

я пишу так:

IplImage* hBitmap2Ipl(HBITMAP hBmp)

{

BITMAP bmp;

::GetObject(hBmp,sizeof(BITMAP),&bmp);

int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel/8;

int depth = IPL_DEPTH_8U;

IplImage* img = cvCreateImageHeader(cvSize(bmp.bmWidth, bmp.bmHeight), depth, nChannels );

cvCreateData(img);

memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels*sizeof(char));

return img;

}




HBITMAP hbm = Image2->Picture->Bitmap->Handle;

img_load2 = hBitmap2Ipl(hbm);

cvFlip(img_load2,img_load2);

но.. при его отрисовки через APIDrawIpl отрисовывается черное окно. при этом изображение там есть.. проверял, писал cvsaveimage.. все сохранило.. дело видимо в самом APIDrawIpl.. если есть идеи.. помогите

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

проблема скорее всего в memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels*sizeof(char));

сдесь ты копируешь биты изображения(BITMAP) bmp.bmBits в imageData. Чтобы их получить тебе надо использовать DC(дескриптор контекста устройства)

HDC DC;

DC = GetDC(0);


//Заполняем массив битов изображения 

int i = GetDIBits( DC, // дескриптор контекста устройства 

HBM, // дескриптор изображения 

0, // первая выбираемая линия для изображения назначения 

BIP->bmiHeader.biHeight, // количество выбираемых линий 

bmp.bmBits, // адрес массива битов изображения 

(BITMAPINFO*)&BIP->bmiHeader,// адрес структуры с данными изображения 

DIB_RGB_COLORS // RGB или индекс палитры 

);

Наверное будет работать) Сам все пробовал методом тыка и интуицией

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

а как тогда объяснить что при cvsaveimage полученное изображение сохраняется полностью ???

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

вот об этом подумал только после того, как написал ответ. Фиг знает

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

и еще а есть функция чтобы наоборот IplImage -> Hbitmap.. ??

Не знаю, по этому поводу не заморачивался.

Память может утекать вот здесь:

>>cvCreateData(img);

наверняка надо использовать cvReleaseData(&img) помимо cvRelease(&img) при завершении работы с изображением. у меня во всяком случае было

img->imageData = (char*) malloc( BM.bmHeight * BM.bmWidth* nChannels * sizeof(char));

free( img->imageData);

Возможно тут:

>>HBITMAP hbm = Image2->Picture->Bitmap->Handle;

Я использую след функции для создания и удаления хбитмапа

HBITMAP bm = CreateBitmap(..);

DeleteObject(bm);

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

С памятью я разобрался!.. Это дело не в этой функции она хорошая.. Там были мои косяки.. тупо про картинку забыл )) На счет после использования достаточно удалить как обычную картинку cvReleaseImage.. HBITMAP я удаляю также

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Не ужели никто не знает как нормально преобразовать Hbitmap в IplImage ??

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вот тут очень простой пример, как сохранить снимок экрана в IplImage через TBitmap:

http://www.compvision.ru/forum/index.php?showtopic=538&view=findpost&p=3340

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

это работает только для борланда?

и еще теоретический вопрос, когда производится запись\чтение через HBITMAP, то из буфера виндоус надо копировать в свой буфер, т.е. дополнительные накладные расходы на копирование или как то можно напрямую сделать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

это работает только для борланда?

Нет, ну конечно чуть чуть редактирования не помешает, но это совсем малость

и еще теоретический вопрос, когда производится запись\чтение через HBITMAP, то из буфера виндоус надо копировать в свой буфер, т.е. дополнительные накладные расходы на копирование или как то можно напрямую сделать.

cvSetImageData(dest, src->Scan0, dest->widthStep); // не тестил, но как-то так
Но, помоему, если мы сделаем UnlockBits() раньше чем, к примеру, покажем картинку, то случится фейл (попробуйте сами). Видимо все зависит от того, как работает функция cvSetImageData() Гляньте сюда, впринципе тож самое http://www.compvisio...findpost&p=3140 Только заменить:
Rect *region = new Rect(0, 0, dest->width, dest->height);

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

я просто не очень понимаю сам смысл действий.

допустим у нас есть IplImage* и чтобы его отрисовать, я выделяю память под HBITMAP и копирую все это в контекст устрйства?

как то так?

вообще с аппаратной точки зрения и по накладным расходам на копирование меня интересует.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×