Jump to content
Compvision.ru
Sign in to follow this  
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> проблему решил. Это оказался только кусок процедуры. Пришлось хорошо поломать голову.

Share this post


Link to post
Share on other sites
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);		

}

Share this post


Link to post
Share on other sites

я пишу так:

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.. если есть идеи.. помогите

Share this post


Link to post
Share on other sites

проблема скорее всего в 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 или индекс палитры 

);

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

и еще а есть функция чтобы наоборот 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);

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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

и еще теоретический вопрос, когда производится запись\чтение через 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);

Share this post


Link to post
Share on other sites

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

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

как то так?

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×