HWND zu IplImage konvertieren
-
Guten Tag,
wie im Titel zu lesen ist möchte ich von einem Fensterhandle (eigl. Fensterklasse)zu einem IplImage kommen. Es geht mir nur um den Client-Bereich.
Ich bin mir jetzt nicht ganz sicher ob das hier das richtige Forum ist, da mein Problem in der memcpy- Funktion liegt.
Die Funktion hab ich mir größtenteils aus Code-Schnipsel zusammengebaut und abgeändert.Beim Aufruf entsteht folgender Fehler:
"Unbehandelte Ausnahme bei 0x6353f2ca (msvcr90d.dll) in Screenshot.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00000000."Hier ist die Funktion:
IplImage *CWndtoIpl(CWnd *pWnd) { HWND hWnd = pwindow->GetSafeHwnd(); CRect rect; pWnd->GetClientRect(rect); int nWidth = rect.right; int nHeight = rect.bottom; HDC hdc = ::GetDC(hWnd); HDC memDC = ::CreateCompatibleDC(hdc); HBITMAP hbm = ::CreateCompatibleBitmap(hdc, nWidth, nHeight); HBITMAP hbmOld = (HBITMAP)::SelectObject(memDC, hbm); BITMAPINFO bmi; ZeroMemory(&bmi, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = nHeight; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 32 * nWidth * nHeight / 8; BYTE *pbBits = new BYTE[bmi.bmiHeader.biSizeImage]; BITMAPFILEHEADER bfh; bfh.bfType = ('M' << 8) + 'B'; bfh.bfSize = sizeof(BITMAPFILEHEADER) + bmi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER); bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // BitBlt(*hDC, 0, 0, GetSystemMetrics(SM_CXSCREEN)-1,GetSystemMetrics(SM_CYSCREEN)-1,memDC, 0, 0, SRCCOPY); HANDLE hfile = CreateFile( "__TMP__SCRNSHOT__2357__.BMP", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0 ); DWORD dwWritten; WriteFile(hfile,&bfh, sizeof(bfh), &dwWritten, NULL); WriteFile(hfile,&bmi.bmiHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL); WriteFile(hfile,pbBits, bmi.bmiHeader.biSizeImage, &dwWritten, NULL); BITMAP bmp; ::GetObject(hbm,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); //memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels*sizeof(char)); //_____________________________________________________________________________________________ CloseHandle(hfile); ::SelectObject(memDC, hbmOld); ::DeleteDC(memDC); ::ReleaseDC(hWnd,hdc); ::DeleteDC(hdc); ::DeleteObject(hbm); ::DeleteObject(hbmOld); ::DeleteObject(hWnd); hbm=NULL; hbmOld=NULL; delete[] pbBits; return img; }
-
Ich habe mitlerweile den Fehler gefunden. bmp.bmBits ist ein Null-Pointer. Ich bin sehr dankbar,
wenn mir jemand zeigen könnte wie ich den Zeiger richtig initialisiere.MfG, Benni
-
Du musst die Bitmap Bits separat anfordern:
http://msdn.microsoft.com/en-us/library/dd144850(v=vs.85).aspx
-
Ich habe das mitlerweile einmal so und so versucht, bin aber
leider zu keinem Ergebnis gekommen. Sprich der Inhalt der
Inhalt von bm.bmpBits ist immernoch 0x0000....//long x = GetBitmapBits(hbm, bmp.bmHeight * bmp.bmWidth * nChannels, bmp.bmBits); //GetDIBits( hdc,hbm,0,bmi.bmiHeader.biHeight,bmp.bmBits,&bmi,DIB_RGB_COLORS);
Was bedeutet es denn wenn im Debugger, nach dem Inhalt einer Variable "{unused=???}" steht? Dies ist bei hbm, hdc, memDC und hbmOld der Fall.
GetBitmapBits liefert nämlich einen richtigen Wert zurück.Falls es weiterhelfen sollte, so wird die Funktion aufgerufen:
void CScreenshotDlg::OnLButtonDown(UINT nFlags, CPoint point) { ... GetCursorPos(&point); pwindow = WindowFromPoint(point); ... test = HWNDtoIpl(pwindow);
Schonmal Danke für die weitere Hilfe!
MfG, Benni
-
Servus,
sorry für denjenigen dem jetzt eventuell 10€ durch die Finger gehen (http://www.c-plusplus.net/forum/293454), aber hier wirst du gehelft:
http://forum.openframeworks.cc/index.php?topic=1414.0
Das sollte dein Problem lösen.
gruß
Hellsgore
-
Hey Hellsgore,
vielen Dank für den Link.
Ich habs jetzt nicht genaus so gemacht
wie dort aber ich hab mir die Lösung ableiten können.Endlich hab ich das hinbekommen, vielen vielen Dank.
MfG, Benni
-
Bitteschön,
aber fein wäre es, wenn du jetzt noch die Lösung posten könntest. Ich denke mal, es könnte noch mehr Leute interessieren...
gruß
Hellsgore
-
OkiliDokili
Soo diese Funktion macht aus einem *CWnd ein IplImage.IplImage *CWndtoIpl(CWnd *pWnd) { CRect rect; HWND hWnd = pwindow->GetSafeHwnd(); pWnd -> GetClientRect(rect); int nWidth = rect.right; int nHeight = rect.bottom; HDC hDC = GetDC(hWnd); HDC hMemDC = CreateCompatibleDC(hDC); IplImage *img; HBITMAP hBitmap = CreateCompatibleBitmap( hDC, nWidth, nHeight); BITMAPINFO bmi; ZeroMemory(&bmi, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = -(nHeight); // Negativ damit das Bild von oben nach unten gemalt wird bmi.bmiHeader.biBitCount = 32; // Farbtiefe des Monitors bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 32 * nWidth * nHeight / 8; BYTE *pbBits = new BYTE[bmi.bmiHeader.biSizeImage]; if( hBitmap) { HBITMAP hOld = (HBITMAP)SelectObject( hMemDC, hBitmap); BitBlt( hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY); SelectObject( hMemDC, hOld); BITMAP bbmp; GetObject( hBitmap, sizeof(BITMAP), &bbmp); int nChannels = bbmp.bmBitsPixel == 1 ? 1 : bbmp.bmBitsPixel/8 ; int depth = bbmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;8U; GetDIBits(hDC, hBitmap, 0, nHeight, pbBits, &bmi,DIB_RGB_COLORS); DeleteObject(hBitmap); img = cvCreateImageHeader( cvSize(bbmp.bmWidth, bbmp.bmHeight), depth, nChannels ); img ->imageData = (char*)malloc(bbmp.bmHeight * bbmp.bmWidth * nChannels * sizeof(char)); memcpy( img->imageData,(char*)(pbBits), bbmp.bmHeight * bbmp.bmWidth * nChannels); } ::DeleteDC(hDC); ::DeleteDC(hMemDC); ::DeleteObject(hWnd); return img; }
MfG,Benni
-
Memory Leak von pbBits!
-
Statt manueller Speicherverwaltung bietet sich hier natürlich
std::vector<BYTE> bits(bmi.bmiHeader.biSizeImage);
an.
Und den CastHBITMAP hOld = (HBITMAP)SelectObject( hMemDC, hBitmap);
kannste dir sparen, wenn hOld ein
HGDIOBJ
ist.Und deklarier Variablen immer so spät wie möglich und initialisiere sie sofort, wann immer dies möglich ist.
-
Gut, ich hab mich jezt über diese Leaks
informiert. Ist das Problem mitdelete pbBits;
gelöst?
-
Nein, pbBits zeigt ja nicht nur auf ein BYTE, sondern auf ein dynamisch reserviertes Array. Folglich müsste es
delete[] pbBits;
heißen.
Aber spar dir doch diese Frickelei (sie ist in C++ unüblich und weist auf einen Codestil der 90er hin) und verwende Container der Standardbibliothek (hier in diesem Beispiel ist der std::vector die bessere Wahl).