I am working with a framegrabber and need to get the images from computer memory and save them on an image file. after trying for couple of days I end up with the following 2 functions, which creates a file and windows OS is able to run the .bmp file, but the bitmap file is black (the image size is 900KB , 640*480). does any body has any idea why, the picture is in black?
here are the two functions :
LPSTR CreateBMP( HWND hAppWnd, int nImageType )
{
void * pWinGBits = NULL;
int i;
Z_BITMAPINFO zWinGHeader; // bitmapinfo for cerating the DIB
// create DC for bitmap.
hDCBits = CreateCompatibleDC( ghDCMain );
switch ( nImageType )
{
case bayer_filter:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize;
zWinGHeader.bmiHeader.biBitCount = 32;
zWinGHeader.bmiHeader.biClrUsed = 0;//3;
zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiColors[0].rgbBlue = 0x00;
zWinGHeader.bmiColors[0].rgbGreen = 0x00;
zWinGHeader.bmiColors[0].rgbRed = 0xFF;
zWinGHeader.bmiColors[0].rgbReserved = 0x00;
zWinGHeader.bmiColors[1].rgbBlue = 0x00;
zWinGHeader.bmiColors[1].rgbGreen = 0xFF;
zWinGHeader.bmiColors[1].rgbRed = 0x00;
zWinGHeader.bmiColors[1].rgbReserved = 0x00;
zWinGHeader.bmiColors[2].rgbBlue = 0xFF;
zWinGHeader.bmiColors[2].rgbGreen = 0x00;
zWinGHeader.bmiColors[2].rgbRed = 0x00;
zWinGHeader.bmiColors[2].rgbReserved = 0x00;
break;
case color32:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/4;
zWinGHeader.bmiHeader.biBitCount = 32;
zWinGHeader.bmiHeader.biClrUsed = 0;
zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiColors[0].rgbBlue = 0x00;
zWinGHeader.bmiColors[0].rgbGreen = 0x00;
zWinGHeader.bmiColors[0].rgbRed = 0xFF;
zWinGHeader.bmiColors[0].rgbReserved = 0x00;
zWinGHeader.bmiColors[1].rgbBlue = 0x00;
zWinGHeader.bmiColors[1].rgbGreen = 0xFF;
zWinGHeader.bmiColors[1].rgbRed = 0x00;
zWinGHeader.bmiColors[1].rgbReserved = 0x00;
zWinGHeader.bmiColors[2].rgbBlue = 0xFF;
zWinGHeader.bmiColors[2].rgbGreen = 0x00;
zWinGHeader.bmiColors[2].rgbRed = 0x00;
zWinGHeader.bmiColors[2].rgbReserved = 0x00;
break;
case color24:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/3;
zWinGHeader.bmiHeader.biBitCount = 24;
zWinGHeader.bmiHeader.biClrUsed = 0;
zWinGHeader.bmiHeader.biCompression = BI_RGB;
zWinGHeader.bmiHeader.biSizeImage = 0;
break;
case color3x16:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/6;
zWinGHeader.bmiHeader.biBitCount = 32;
zWinGHeader.bmiHeader.biClrUsed = 0;
zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiColors[0].rgbBlue = 0x00;
zWinGHeader.bmiColors[0].rgbGreen = 0x00;
zWinGHeader.bmiColors[0].rgbRed = 0xFF;
zWinGHeader.bmiColors[0].rgbReserved = 0x00;
zWinGHeader.bmiColors[1].rgbBlue = 0x00;
zWinGHeader.bmiColors[1].rgbGreen = 0xFF;
zWinGHeader.bmiColors[1].rgbRed = 0x00;
zWinGHeader.bmiColors[1].rgbReserved = 0x00;
zWinGHeader.bmiColors[2].rgbBlue = 0xFF;
zWinGHeader.bmiColors[2].rgbGreen = 0x00;
zWinGHeader.bmiColors[2].rgbRed = 0x00;
zWinGHeader.bmiColors[2].rgbReserved = 0x00;
break;
case bw1x10:
// create bitmap-infoheader.
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biBitCount = 8;
zWinGHeader.bmiHeader.biCompression = BI_RGB;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiHeader.biClrUsed = 256;
zWinGHeader.bmiHeader.biClrImportant= 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/2;
// create colortable fot bitmap (grayvalues).
for (i = 0; i < 256; i++)
{
zWinGHeader.bmiColors[i].rgbGreen = i;
zWinGHeader.bmiColors[i].rgbBlue = i;
zWinGHeader.bmiColors[i].rgbRed = i;
zWinGHeader.bmiColors[i].rgbReserved = 0;
}
break;
default:
case bw8:
// create bitmap-infoheader.
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biBitCount = 8;
zWinGHeader.bmiHeader.biCompression = BI_RGB;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiHeader.biClrUsed = (1<<8);
zWinGHeader.bmiHeader.biClrImportant= 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize;
//zWinGHeader.bmiHeader.biSizeImage = ((zWinGHeader.bmiHeader.biWidth * 8 +31) & ~31) /8
// * zWinGHeader.bmiHeader.biHeight;
// create colortable fot bitmap (grayvalues).
for (i = 0; i < 256; i++)
{
zWinGHeader.bmiColors[i].rgbGreen = i;
zWinGHeader.bmiColors[i].rgbBlue = i;
zWinGHeader.bmiColors[i].rgbRed = i;
zWinGHeader.bmiColors[i].rgbReserved = 0;
}
break;
}
// cerate identity palette
hPal = CreateIdentityPalette( zWinGHeader.bmiColors );
// get new palette into DC and map into physical palette register.
hOldPal = SelectPalette( ghDCMain, hPal, FALSE);
RealizePalette( ghDCMain );
// cerate DIB-Section f黵 direct access of image-data.
hBitmap = CreateDIBSection(
hDCBits, // handle of device context
(BITMAPINFO *)&zWinGHeader, // address of structure containing
// bitmap size, format and color data
DIB_RGB_COLORS, // color data type indicator: RGB values
// or palette indices
&pWinGBits, // pointer to variable to receive a pointer
// to the bitmap's bit values
NULL, // optional handle to a file mapping object
0 // offset to the bitmap bit values within
// the file mapping object
);
// get bitmap into DC .
hOldBitmap = (HBITMAP)SelectObject( hDCBits, hBitmap );
return pWinGBits; // return pointer to DIB
}
and here is the function for saving into .bmp :
BOOL SaveToFile(HBITMAP hBitmap3, LPCTSTR lpszFileName)
{
HDC hDC;
int iBits;
WORD wBitCount;
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
BITMAP Bitmap0;
BITMAPFILEHEADER bmfHdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh, hDib, hPal,hOldPal2=NULL;
hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits <= 1)
wBitCount = 1;
else if (iBits <= 4)
wBitCount = 4;
else if (iBits <= 8)
wBitCount = 8;
else
wBitCount = 24;
GetObject(hBitmap3, sizeof(Bitmap0), (LPSTR)&Bitmap0);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap0.bmWidth;
bi.biHeight =-Bitmap0.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 256;
dwBmBitsSize = ((Bitmap0.bmWidth * wBitCount +31) & ~31) /8
* Bitmap0.bmHeight;
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = GetDC(NULL);
hOldPal2 = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
GetDIBits(hDC, hBitmap3, 0, (UINT) Bitmap0.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
if (hOldPal2)
{
SelectPalette(hDC, (HPALETTE)hOldPal2, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
}
fh = CreateFile(lpszFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE)
return FALSE;
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
counter=1;
return TRUE;
}
I CAN Draw the images from memory perfectly with the following function, so for sure I dont have any problem for reading the image data :
void DrawPicture( HDC hDC, PBYTE pDest, PBYTE pSrc, LONG lXSize, LONG lYSize )
{
LONG lXSizeDiv, lYSizeDiv;
LONG lX, lY;
DWORD dwMax;
RECT rect;
HDC hdc;
PBYTE pTmpDest;
double fXFactor, fYFactor;
// HBRUSH hBrush;
// POINT Point;
switch( gzMvfgKamDef.iImageType )
{
case bayer_filter:
lXSizeDiv = 1;
lYSizeDiv = 1;
BayerToRGB( (PDWORD) pDest, pSrc, lXSize, lYSize,
gzMvfgKamDef.iBayerQuadrant, gzMvfgKamDef.iBayerQuality );
break;
case color24:
lXSizeDiv = 3;
lYSizeDiv = 1;
memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) );
break;
case color32:
lXSizeDiv = 4;
lYSizeDiv = 1;
memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) );
break;
case color3x16:
lXSizeDiv = 6;
lYSizeDiv = 1;
Conv3x16To3x8( pDest, pSrc, 4, lXSize, lYSize );
break;
case bw1x10:
lXSizeDiv = 2;
lYSizeDiv = 1;
Conv1x10To1x8( pDest, pSrc, 2, lXSize, lYSize );
break;
case bw6Tap:
lXSizeDiv = 1;
lYSizeDiv = 1;
Conv6TapTo1x8( pDest, pSrc, 1, lXSize, lYSize );
break;
default:
case bw8:
lXSizeDiv = 1;
lYSizeDiv = 1;
memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) );
break;
}
if( gahIniDlg[ NdxHistogramDlg ].hWnd )
{
memset( gadwHistogram, 0, sizeof( gadwHistogram) );
pTmpDest = pDest;
for ( lY = 0; lY < lYSize; lY++ )
{
for ( lX = 0; lX < lXSize; lX++ )
{
gadwHistogram[ *pTmpDest ]++;
pTmpDest++;
}
}
GetClientRect ( gahIniDlg[ NdxHistogramDlg ].hWnd, &rect) ;
hdc = GetDC ( gahIniDlg[ NdxHistogramDlg ].hWnd );
dwMax = 0;
for ( lX = 0 ; lX <= 0xff; lX++ )
dwMax = ( gadwHistogram[ lX ] > dwMax ) ? gadwHistogram[ lX ] : dwMax;
fYFactor = (double) dwMax / (double) rect.bottom;
fXFactor = (double) ( rect.right - 100 ) / (double) 0x100;
/*
SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
for( lX = 0; lX <= 0xff; lX+=8 )
{
MoveToEx( hdc, lX * fXFactor, rect.bottom, &Point );
LineTo( hdc, lX * fXFactor, rect.bottom-10 );
}
*/
SelectObject (hdc, GetStockObject (WHITE_PEN)) ;
// hBrush = CreateSolidBrush( GetSysColor( COLOR_WINDOW ));
// hBrush = CreateSolidBrush( 0xffffff );
// SelectObject (hdc, hBrush);
Polyline( hdc, gaHistogram, 0x100 );
// DeleteObject( hBrush );
for ( lX = 0 ; lX <= 0xff; lX++ )
{
gaHistogram[ lX ].x = (DWORD)( fXFactor * (double)lX );
gaHistogram[ lX ].y = rect.bottom - (DWORD)( (double) gadwHistogram[ lX ] / fYFactor );
}
SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
Polyline( hdc, gaHistogram, 0x100 );
ReleaseDC ( gahIniDlg[ NdxHistogramDlg ].hWnd , hdc ) ;
}
// display the bitmap
StretchBlt( hDC, rcWin.left, rcWin.top, lXSize / lXSizeDiv, lYSize / lYSizeDiv,
hDCBits, 0, 0, lXSize / lXSizeDiv, lYSize / lYSizeDiv, SRCCOPY );
//BitBlt( hDC, rcWin.left, rcWin.top, lXSize / lXSizeDiv, lYSize / lYSizeDiv,
//hDCBits, 0, 0, SRCCOPY );
}
I just find out I had a silly mistake in another part of my code I was using :
// Convert Image to bitmap and display it
DrawPicture( ghDCMain, pWinGBitmap, gpbImageData, lXSize, lYSize );
if(counter!=1) {
hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize);
SaveToFile(hBitmap2, "c:\\t.bmp");
OutputDebugString("tested !!!!");
}
by deleting the hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize); line, and changing the hBitmap2 to hBitmap the result of CreateDIBSection(), it saved the image beautifully. THANK YOU EVERYONE FOR YOUR HELP.
FORMAT_INFO sFormat;
mvfg_getparam( MVFGPAR_DATAFORMAT, &sFormat, giCurrentGrabberID);
long lFrameSize = sFormat.lFrameSize;
BYTE *pBitmap = (BYTE*)malloc(FrameSize);
memcpy( pBitmap, CamGetPicture(), FrameSize );
writeBitmapToFile(pBitmap, FrameSize, "tmp.bmp");
/*
* write our raw data into a bitmap file
* adding the correct header and put it all
* together in a single file
*/
int
writeBitmapToFile(void *data, unsigned long size, const char *filename)
{
bmpFileHeader_t header;
bmpInfoHeader_t info;
bmpRGBQuad_t rgb = { 0, 0, 0, 0};
FILE *out;
size_t len;
int i;
header.type = 0x4d42; // magic sequence 'BM'
header.size = 0;
header.res0 = 0;
header.res1 = 0;
/* 256 different colors, each is defined by an bmpRBQuad type */
header.offset = 256 * sizeof(bmpRGBQuad_t) +
sizeof(bmpInfoHeader_t) + sizeof(bmpFileHeader_t);
info.size = sizeof(bmpInfoHeader_t);
info.width = WIDTH;
info.height = HEIGHT;
info.planes = 1;
info.cDepth = 8; /* 8 Bit */
info.compression = 0;
info.rawSize = size;
info.hRes = 0;
info.vRes = 0;
info.nrColors = 0x100;
info.impColors = 0;
out = fopen(filename, "wb");
if (out == NULL) {
printf("error cannot open %s for writing\n", filename);
return -1;
}
len = fwrite(&header, 1, sizeof(header), out);
if (len != sizeof(header)) {
printf("error while writing header\n");
return -1;
}
len = fwrite(&info, 1, sizeof(info), out);
if (len != sizeof(info)) {
printf("error while writing info header\n");
return -1;
}
/* stupid try and error programming leads to this */
for (i = 0; i < 256; i++) {
rgb.red = i;
rgb.green = i;
rgb.blue = i;
len = fwrite(&rgb, 1, sizeof(rgb), out);
if (len != sizeof(rgb)) {
printf("error while writing rgb header\n");
return -1;
}
}
len = fwrite(data, 1, size, out);
if (len != size ) {
printf("error while writing bitmap data\n");
return -1;
}
return 0;
}
Reference - mikrotron
Reference - write bitmap
Are you sure there is proper data in there?
I would try extract the RGB data and save it in some very simple format "manually", just to see what is in there. If you are looking for a dead simple but still standard image format, look at PPM images.
From the documentation for CreateCompatibleDC:
When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC.
Since you're using CreateDIBSection with that DC, the resulting DIB section will be 1-bit monochrome as well.
Related
I am using the following code to take a screenshot in C on Windows (from https://learn.microsoft.com/en-us/windows/win32/gdi/capturing-an-image).
int captureImage(HWND hWnd, char * filename){
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
DWORD dwBytesWritten = 0;
DWORD dwSizeofDIB = 0;
HANDLE hFile = NULL;
char* lpbitmap = NULL;
HANDLE hDIB = NULL;
DWORD dwBmpSize = 0;
// retrieve handle to display device content
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
// Create a compatible DC (domain controller)
hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC){
printf("Error creating hdcMemDC\n");
return 1;
}
// Make process DPI aware to avoid wrongly sized screenshots when screen resolution changes
SetProcessDPIAware();
// get area for size calculations
RECT rcClient;
GetClientRect(hWnd, &rcClient);
// use this stretch mode
SetStretchBltMode(hdcWindow, HALFTONE);
// the source DC is the entire screen, and the destination in the current window (for now)
StretchBlt(hdcWindow, 0, 0, rcClient.right, rcClient.bottom, hdcScreen, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SRCCOPY);
// create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
if (!hbmScreen){
printf("Error creating hmbScreen\n");
return 1;
}
// Select the compatible bitmap into the memory DC
SelectObject(hdcMemDC, hbmScreen);
// transfer bits into the memory DC
BitBlt(hdcMemDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcWindow, 0 , 0, SRCCOPY);
// get the bitmap from the hbitmap
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
// bitmap file header and info header
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
// set all values for info header
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount+31) / 32) * 4 * bmpScreen.bmHeight;
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);
// get the bits from the bitmap and copy them into the buffer
GetDIBits(hdcWindow, hbmScreen, 0, (UINT)bmpScreen.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
// create a file to save the capture into
hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// get the total size of the file
dwSizeofDIB = dwBmpSize + (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
// offset to where our bitmap actually starts
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
// size of the file
bmfHeader.bfSize = dwSizeofDIB;
// always set bfType to BM for bitmaps
bmfHeader.bfType = 0x4D42; // that's BM
// write data to the file
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
// unlock and free stuff
GlobalUnlock(hDIB);
GlobalFree(hDIB);
// close file handle
CloseHandle(hFile);
// Clean everything up
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return 0; // for normal exit
}
Passing in the return value of GetDesktopWindow() will take a screenshot of the entire screen and save it a to a file with filename. The screenshot is the size of and has the resolution of the screen. So, if used on a 4k screen, that will be the resolution of the screenshot. I was wondering what the best way was to cap this at, say, 1080p. So even if the resolution is greater than 1080x1920, the screenshot will not go higher.
use such code
ULONG captureImage(_In_ ULONG cx, _In_ PCWSTR filename)
{
struct BMEX
{
USHORT ForAlign;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
UCHAR Bits[];
};
ULONG cxScreen = GetSystemMetrics(SM_CXSCREEN), cyScreen = GetSystemMetrics(SM_CYSCREEN);
ULONG cy = cyScreen * cx / cxScreen;
ULONG size = ((3 * cx + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1)) * cy;
ULONG dwError;
if (HANDLE hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size + sizeof(BMEX), 0))
{
BITMAPINFO bi = {
{ sizeof(BITMAPINFOHEADER), cx, cy, 1, 24, BI_RGB, size }
};
PVOID Bits;
if (HBITMAP hbmp = CreateDIBSection(0, &bi, DIB_RGB_COLORS, &Bits, hSection, __builtin_offsetof(BMEX, Bits)))
{
if (HDC hdc = GetDC(0))
{
if (HDC hMemDC = CreateCompatibleDC(0))
{
HGDIOBJ h = SelectObject(hMemDC, hbmp);
if (StretchBlt(hMemDC, 0, 0, cx, cy, hdc, 0, 0, cxScreen, cyScreen, SRCCOPY))
{
HANDLE hFile = CreateFileW(filename, FILE_APPEND_DATA, 0, 0, CREATE_ALWAYS, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
BMEX* p = CONTAINING_RECORD(Bits, BMEX, Bits);
p->bfh.bfType = 'MB';
p->bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
p->bfh.bfSize = size += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
p->bfh.bfReserved1 = 0;
p->bfh.bfReserved2 = 0;
memcpy(&p->bih, &bi.bmiHeader, sizeof(BITMAPINFOHEADER));
dwError = WriteFile(hFile, &p->bfh, size, &size, 0) ? NOERROR : GetLastError();
CloseHandle(hFile);
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
SelectObject(hMemDC, h);
DeleteDC(hMemDC);
}
else
{
dwError = GetLastError();
}
ReleaseDC(0, hdc);
}
else
{
dwError = GetLastError();
}
DeleteObject(hbmp);
}
else
{
dwError = GetLastError();
}
CloseHandle(hSection);
return dwError;
}
return GetLastError();
}
I'm trying to initialize a setup in Vulkan where within the Shader there is a uniform array of textures and an corresponding arrays for the textures Width and Heights:
layout(binding=0) uniform UniformBufferObject {
mat4 model; //4x4 array of floats for uniform rotation and positioning
uint texW[32]; //Widths of ith texture
uint texH[32]; //Heights of ith texture
} ubo;
For some reason the shader only reads the mat4 and the first index of the texW. Everything else is initialized to 0.
Here's the Uniform Buffer Setup Code, for reference
void createUniformBuffers() {
/**Uniform Buffer for View Transformation*/
VkDeviceSize bufferSize = sizeof(uniformBufferObject);
uniformBuffers = malloc(swapChainSize * sizeof(VkBuffer));
uniformBuffersMemory = malloc(swapChainSize * sizeof (VkDeviceMemory));
for(uint i = 0; i < swapChainSize; i++)
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffers[i], &uniformBuffersMemory[i]);
}
void createDescriptorPool() {
VkDescriptorPoolSize poolSizes[4];
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount = swapChainSize;
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[1].descriptorCount = swapChainSize;
VkDescriptorPoolCreateInfo poolInfo;
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.pNext = 0;
poolInfo.flags = 0;
poolInfo.poolSizeCount = 2;
poolInfo.pPoolSizes = poolSizes;
poolInfo.maxSets = swapChainSize;
if(vkCreateDescriptorPool(lDevice, &poolInfo, 0, & descriptorPool)) {
fprintf(stderr, "Failed to create Descriptor Pool\n");
exit(1);
}
}
void createDescriptorSets() {
VkDescriptorSetLayout layouts[swapChainSize];
for(uint i = 0; i < swapChainSize; i++) layouts[i] = descriptorSetLayout;
VkDescriptorSetAllocateInfo allocInfo;
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.pNext = 0;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = swapChainSize;
allocInfo.pSetLayouts = layouts;
descriptorSets = malloc(sizeof(VkDescriptorSet) * swapChainSize);
if(vkAllocateDescriptorSets(lDevice, &allocInfo, descriptorSets) ) {
fprintf(stderr,"Failed to allocate descriptor sets\n");
exit(1);
}
for(uint i = 0; i < swapChainSize; i++) {
VkDescriptorBufferInfo bufferInfo;
bufferInfo.buffer = uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = VK_WHOLE_SIZE; //sizeof(uniformBufferObject);
VkWriteDescriptorSet descriptorWrites[2];
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].pNext = 0;
descriptorWrites[0].dstSet = descriptorSets[i];
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrites[0].descriptorCount = 1;
descriptorWrites[0].pBufferInfo = &bufferInfo;
descriptorWrites[0].pImageInfo = 0;
descriptorWrites[0].pTexelBufferView = 0;
descriptorWrites[0].dstArrayElement = 0;
VkDescriptorImageInfo imageInfo;
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = textureImageView[0];
imageInfo.sampler= textureSampler;
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].pNext = 0;
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstSet = descriptorSets[i];
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrites[1].descriptorCount = 1;
descriptorWrites[1].pImageInfo = &imageInfo;
descriptorWrites[1].pBufferInfo = 0;
descriptorWrites[1].pTexelBufferView = 0;
descriptorWrites[1].dstArrayElement = 0;
vkUpdateDescriptorSets(lDevice, 2, descriptorWrites,0,0);
}
}
Here's the code where the uniformBuffer is updated,
void updateUniformBuffer(uint currentImage) {
//FTR, I know I probably shouldn't remap each update, optimizing this is on my todo-list
vkMapMemory(lDevice, uniformBuffersMemory[currentImage], 0, sizeof(uniformBufferObject), 0, (void*) &uData);
memcpy(uData, &uniformData, sizeof(uniformBufferObject));
memset(uData->model, 0, sizeof(uData->model));
//Rotating the View, GLSL acknowledges this data
uData->model[2][2] = uData->model[3][3] = 1;
uData->model[0][0] = cosf(angle);
uData->model[0][1] = -sinf(angle);
uData->model[1][1] = cosf(angle);
uData->model[1][0] = sinf(angle);
angle+= 0.05f;
uData->texW[0] = 1024; //<-------GLSL Vertex Shader will acknowledge this =)
uData->texH[0] = 1024; //<-------GLSL Vertex Shader will ignore this =(
uData->texH[0] = 1024; //<-------GLSL Vertex Shader will also ignore this >_<
vkUnmapMemory(lDevice,uniformBuffersMemory[currentImage]);}
Any pointers or advice would be greatly appreciated.
I have an image to load into my GUI, using the win32 library. It's too large and so the entire image does not get displayed.
Below is the code for the window and painting the image onto the window.
The target image is 1600 pixels wide and 1140 pixels tall.
LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
HMENU hMenu;
OPENFILENAME ofn;
FILE *fpt;
HDC hDC;
char header[320],text[320];
int BYTES,xPos,yPos;
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_CLEARIMAGE:
//Clear image
PaintImage();
break;
case ID_FILE_LOAD:
if (OriginalImage != NULL || image_loaded == 1)
{
for (int i = 0; i < 1500; i++)
{
for (int j = 0; j < 1500; j++)
{
OriginalImage[i * COLS + j] = 255;
}
}
OriginalImage = NULL;
free(OriginalImage);
}
memset(&(ofn),0,sizeof(ofn));
ofn.lStructSize=sizeof(ofn);
ofn.lpstrFile=filename;
filename[0]=0;
ofn.nMaxFile=MAX_FILENAME_CHARS;
ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
ofn.lpstrFilter = "PNM files\0*.pnm\0All files\0*.*\0\0";
if (!( GetOpenFileName(&ofn)) || filename[0] == '\0')
break; /* user cancelled load */
if ((fpt=fopen(filename,"rb")) == NULL)
{
MessageBox(NULL,"Unable to open file",filename,MB_OK | MB_APPLMODAL);
break;
}
fscanf(fpt,"%s\n%d %d\n%d",header,&COLS,&ROWS,&BYTES);
if (strcmp(header,"P6") != 0 || BYTES != 255)
{
MessageBox(NULL,"Not a PNM image",filename,MB_OK | MB_APPLMODAL);
fclose(fpt);
break;
}
OriginalImage=(unsigned char *)calloc(ROWS*COLS*3,1);
header[0]=fgetc(fpt); /* whitespace character after header */
fread(OriginalImage,1,ROWS*COLS*3,fpt);
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
OriginalImage[i * COLS + j] = (int)(OriginalImage[i * (COLS * 3) + (j * 3)] +
OriginalImage[i * (COLS * 3) + (j * 3) + 1] +
OriginalImage[i * (COLS * 3) + (j * 3) + 2])/3.0;
}
}
image_loaded = 1;
fclose(fpt);
SetWindowText(hWnd,filename);
PaintImage();
break;
case ID_FILE_QUIT:
DestroyWindow(hWnd);
break;
}
break;
case WM_SIZE: /* could be used to detect when window size changes */
PaintImage();
return(DefWindowProc(hWnd,uMsg,wParam,lParam));
break;
case WM_PAINT:
PaintImage();
return(DefWindowProc(hWnd,uMsg,wParam,lParam));
break;
Below is the paint function
void PaintImage()
{
PAINTSTRUCT Painter;
HDC hDC;
BITMAPINFOHEADER bm_info_header;
BITMAPINFO *bm_info;
int i,r,c,DISPLAY_ROWS,DISPLAY_COLS;
unsigned char *DisplayImage;
HDC hdcScaled;
HBITMAP hbmScaled;
if (OriginalImage == NULL)
return; /* no image to draw */
/* Windows pads to 4-byte boundaries. We have to round the size up to 4 in each dimension, filling with black. */
DISPLAY_ROWS=ROWS;
DISPLAY_COLS=COLS;
if (DISPLAY_ROWS % 4 != 0)
DISPLAY_ROWS=(DISPLAY_ROWS/4+1)*4;
if (DISPLAY_COLS % 4 != 0)
DISPLAY_COLS=(DISPLAY_COLS/4+1)*4;
DisplayImage=(unsigned char *)calloc(DISPLAY_ROWS*DISPLAY_COLS,1);
for (r=0; r<ROWS; r++)
for (c=0; c<COLS; c++)
DisplayImage[r*DISPLAY_COLS+c] = OriginalImage[r*COLS+c];
BeginPaint(MainWnd,&Painter);
hDC=GetDC(MainWnd);
bm_info_header.biSize=sizeof(BITMAPINFOHEADER);
bm_info_header.biWidth=DISPLAY_COLS;
bm_info_header.biHeight=-DISPLAY_ROWS;
bm_info_header.biPlanes=1;
bm_info_header.biBitCount=8;
bm_info_header.biCompression=BI_RGB;
bm_info_header.biSizeImage=0;
bm_info_header.biXPelsPerMeter=0;
bm_info_header.biYPelsPerMeter=0;
bm_info_header.biClrUsed=256;
bm_info_header.biClrImportant=256;
bm_info=(BITMAPINFO *)calloc(1,sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD));
bm_info->bmiHeader=bm_info_header;
for (i=0; i<256; i++)
{
bm_info->bmiColors[i].rgbBlue = bm_info->bmiColors[i].rgbGreen = bm_info->bmiColors[i].rgbRed = i;
bm_info->bmiColors[i].rgbReserved=0;
}
SetDIBitsToDevice(hDC,0,0,DISPLAY_COLS,DISPLAY_ROWS,0,0,
0, /* first scan line */
DISPLAY_ROWS, /* number of scan lines */
DisplayImage,bm_info,DIB_RGB_COLORS);
hdcScaled = CreateCompatibleDC(hDC);
hbmScaled = CreateCompatibleBitmap(hDC, GetDeviceCaps(hDC, HORZRES) * 0.5, GetDeviceCaps(hDC, VERTRES) * 0.5);
ReleaseDC(MainWnd,hDC);
EndPaint(MainWnd,&Painter);
free(DisplayImage);
free(bm_info);
}
The following is a link I found on resizing/rescaling images, but I don't understand how to implement it using my code.
C++ WIN32: Rescaling Bitmaps/Giving Bitmaps HDC's
Please advise.
The StretchBlt method is pointed out in the link.
Add the following code in PaintImage(),
void PaintImage()
{
for (i=0; i<256; i++)
{
bm_info->bmiColors[i].rgbBlue = bm_info->bmiColors[i].rgbGreen = bm_info->bmiColors[i].rgbRed = i;
bm_info->bmiColors[i].rgbReserved=0;
}
...
RECT rc;
GetClientRect(MainWnd, &rc);
hdcScaled = CreateCompatibleDC(hDC);
hbmScaled = CreateCompatibleBitmap(hDC, DISPLAY_COLS, DISPLAY_ROWS);
SelectObject(hdcScaled, hbmScaled);
SetDIBitsToDevice(hdcScaled, 0, 0, DISPLAY_COLS, DISPLAY_ROWS, 0, 0,
0, /* first scan line */
DISPLAY_ROWS, /* number of scan lines */
DisplayImage, bm_info, DIB_RGB_COLORS);
SetStretchBltMode(hDC, HALFTONE);
StretchBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdcScaled, 0, 0, DISPLAY_COLS, DISPLAY_ROWS, SRCCOPY);
DeleteObject(hdcScaled);
DeleteObject(hbmScaled);
...
}
Note: Delete objects to avoid memory leaks
You could use the CAPI library. It has a very easy to use image stretch functions
capi_DrawImageEx
capi_DrawImageExA
Here is a simple example program that demonstrates stretching an image to fit into a window.
#include <Windows.h>
#include <CAPI.h>
#define WinClassName STR("ExampleProgram")
#define WinTitle STR("Example Program")
#ifdef UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#define ApplicationEntryPoint wWinMain
#else
#define app_fopen fopen_s
#define app_printf printf
#define ApplicationEntryPoint WinMain
#endif // UNICODE
static HWND Window_hWnd = 0;
static HDC BufferHDC = 0;
static BITMAPINFO* pDisplayBitmap = 0;
static HBITMAP hBitmap = 0;
static int ClientWidth;
static int ClientHeight;
static IMAGE FrameBuffer;
static IMAGE exampleImage;
void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
FILE* Stream;
size_t BufferLength;
void* pThisFile;
void* pNewBlock;
if ((FilePath == 0) || (pFileSize == 0)) return 0;
*pFileSize = 0;
if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
if (Stream == 0) return 0;
pThisFile = 0;
BufferLength = 0;
do
{
BufferLength += 0x1000;
pNewBlock = capi_realloc(pThisFile, BufferLength);
if (pNewBlock == 0)
{
if (pThisFile != 0) capi_free(pThisFile);
fclose(Stream);
return 0;
}
pThisFile = pNewBlock;
*pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
} while (!(feof(Stream)));
fclose(Stream);
return pThisFile;
}
I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
FILE* Stream;
size_t nBytesWrite;
I32 ErrorCode;
if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;
ErrorCode = CAPI_ERROR_NONE;
if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;
nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
if (nBytesWrite != FileSize)
{
ErrorCode = CAPI_ERROR_ACCESS_DENIED;
goto exit_func;
}
exit_func:
fclose(Stream);
return ErrorCode;
}
void FreeSysInternal()
{
if (BufferHDC != 0)
{
DeleteDC(BufferHDC);
BufferHDC = 0;
}
if (pDisplayBitmap != 0)
{
capi_free(pDisplayBitmap);
pDisplayBitmap = 0;
}
if (hBitmap != 0)
{
DeleteObject(hBitmap);
hBitmap = 0;
}
}
U32 SetupWindowFrameBuffer(HDC WindowHDC, RECT* ClientRt)
{
FreeSysInternal();
pDisplayBitmap = (BITMAPINFO*)capi_malloc(sizeof(BITMAPINFOHEADER));
if (pDisplayBitmap == 0) return 1;
pDisplayBitmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pDisplayBitmap->bmiHeader.biWidth = ClientRt->right;
pDisplayBitmap->bmiHeader.biHeight = -ClientRt->bottom;
pDisplayBitmap->bmiHeader.biPlanes = 1;
pDisplayBitmap->bmiHeader.biBitCount = 32;
pDisplayBitmap->bmiHeader.biCompression = 0;
pDisplayBitmap->bmiHeader.biSizeImage = 0;
pDisplayBitmap->bmiHeader.biXPelsPerMeter = 0;
pDisplayBitmap->bmiHeader.biYPelsPerMeter = 0;
pDisplayBitmap->bmiHeader.biClrUsed = 0;
pDisplayBitmap->bmiHeader.biClrImportant = 0;
BufferHDC = CreateCompatibleDC(WindowHDC);
if (BufferHDC == 0)
{
capi_free(pDisplayBitmap);
return 2;
}
hBitmap = CreateDIBSection(BufferHDC, pDisplayBitmap, 0,
(void**)&FrameBuffer.Pixels, 0, 0);
if (hBitmap == 0)
{
DeleteDC(BufferHDC);
capi_free(pDisplayBitmap);
return 3;
}
GdiFlush();
FrameBuffer.ScanLine = ClientRt->right;
FrameBuffer.Width = ClientRt->right;
FrameBuffer.Height = ClientRt->bottom;
SelectObject(BufferHDC, hBitmap);
return 0;
}
void Window_Paint_Handler(IMAGE* pDisplay)
{
// Fill the background of our window.
capi_FillImage(pDisplay, COLOR(195, 195, 195, 255));
// Now we stretch our test image to the size of the window.
// Note: The last parameter (Alpha) must be 255 for the image to be displayed normally.
capi_DrawImageExA(pDisplay, &exampleImage, 0, 0, DRAW_RESIZE_BOXSAMP, pDisplay->Width, pDisplay->Height, 255);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC WinDC;
PAINTSTRUCT ps;
RECT WinArea;
RECT ClientArea;
int BorderWidth;
int BorderHeight;
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
{
WinDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &ClientArea);
if ((ClientArea.right == 0) || (ClientArea.bottom == 0)) goto exit_paint_message;
if ((ClientArea.right != FrameBuffer.Width) || (ClientArea.bottom != FrameBuffer.Height))
{
if (SetupWindowFrameBuffer(WinDC, &ClientArea) != 0) goto exit_paint_message;
}
Window_Paint_Handler(&FrameBuffer);
SetDIBits(BufferHDC, hBitmap, 0,
pDisplayBitmap->bmiHeader.biHeight, FrameBuffer.Pixels, pDisplayBitmap, 0);
BitBlt(WinDC, 0, 0, ClientArea.right, ClientArea.bottom, BufferHDC, 0, 0, 0x00CC0020);
exit_paint_message:
EndPaint(hWnd, &ps);
break;
}
case WM_CREATE:
{
Window_hWnd = hWnd;
GetWindowRect(hWnd, &WinArea);
GetClientRect(hWnd, &ClientArea);
BorderWidth = WinArea.right - ClientArea.right;
BorderHeight = WinArea.bottom - ClientArea.bottom;
SetWindowPos(hWnd, NULL,
0, 0,
BorderWidth + ClientWidth, BorderHeight + ClientHeight, SWP_NOMOVE | SWP_NOZORDER);
GetWindowRect(hWnd, &WinArea);
SetWindowPos(hWnd, NULL,
(GetSystemMetrics(SM_CXSCREEN) - (WinArea.right - WinArea.left)) / 2,
(GetSystemMetrics(SM_CYSCREEN) - (WinArea.bottom - WinArea.top)) / 2,
0, 0, SWP_NOSIZE | SWP_NOZORDER);
break;
}
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI ApplicationEntryPoint(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ STRING* pCmdLine, _In_ int nCmdShow)
{
MSG msg;
WNDCLASSEX wcex;
void* myLoadedFile;
U64 FileSize;
I32 ErrorCode;
// Load our image to draw to the window frame buffer.
myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
if (myLoadedFile == 0)
{
MessageBox(0, STR("LoadFile Failed."), STR("Error!"), MB_OK);
return 0;
}
ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
if (ErrorCode != CAPI_ERROR_NONE)
{
MessageBox(0, STR("capi_LoadImageFromMemory Failed."), STR("Error!"), MB_OK);
return 0;
}
// The client area of our window will be the same size as our test image.
ClientWidth = exampleImage.Width;
ClientHeight = exampleImage.Height;
// Create the display window and enter the thread/window message loop.
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = WinClassName;
wcex.hIconSm = NULL;
if (!RegisterClassEx(&wcex))
{
MessageBox(0, STR("Failed to register the window class."), STR("Error!"), MB_OK);
return 0;
}
// Note: The 700 (Width) and 500 (Height) values are just dummy values. The Width and Height get set in the WM_CREATE message handler.
CreateWindowEx(0, WinClassName, WinTitle,
WS_VISIBLE | WS_CLIPCHILDREN | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX,
0, 0, 700, 500, NULL, NULL, hInstance, NULL);
if (!Window_hWnd)
{
MessageBox(0, STR("Failed to create the window."), STR("Error!"), MB_OK);
return 0;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
FreeSysInternal();
return 0;
}
My program segfaults as soon as I press a key, but I am unable to come up with a minimal code. If I comment out pixels[y][pdpix] = col[sampleX][sampleY]; (line 110), key presses work as normal. Otherwise, it segfaults.
Full code and "bmp" files: https://drive.google.com/file/d/1663hiKbvodcNu0xG8FpbYACAUoGScfAn/view?usp=sharing
Code in main.c:
#include <SDL2/SDL.h>
#include <stdbool.h>
#include "read.h"
#define RESX 960
#define RESY 540
#define HRESX 480
#define DRAWDISTANCE 360
#define ROTSPEED 0.005
#define BGCOL 0
#define ARESY 539
void main() {
readCW();
bool running = true;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
running = false;
}
window = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, RESX, RESY, SDL_WINDOW_SHOWN );
if( window==NULL) {
printf( "SDL_Error: %s\n", SDL_GetError() );
running = false;
}
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
if(renderer==NULL) {
printf("Renderer error: %s\n", SDL_GetError() );
running = false;
}
SDL_Texture * texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, RESX,RESY);
readBW();
float playerX = 512;
float playerY = 512;
float dirX = 0.0;
float dirY = 1.0;
void rotatez(float rotspeed) {
float oldDirX = dirX;
dirX = dirX * cos(rotspeed) - dirY * sin(rotspeed);
dirY = oldDirX * sin(rotspeed) + dirY * cos(rotspeed);
}
const Uint8* keystate = SDL_GetKeyboardState( NULL );
while( running ) {
clock_t t1, t2;
t1 = SDL_GetTicks();
Uint32 pixels[RESY][RESX] = {[0 ... RESY-1][0 ...RESX-1] = 0x5555FF};
SDL_Event e;
running = !(SDL_PollEvent( &e ) && e.type == SDL_QUIT);
if(keystate[SDL_SCANCODE_ESCAPE]) running = false;
if(keystate[SDL_SCANCODE_LEFT]) rotatez(-ROTSPEED);
if(keystate[SDL_SCANCODE_RIGHT]) rotatez(ROTSPEED);
if(keystate[SDL_SCANCODE_W]) {
playerY += dirY;
playerX += dirX;
}
if(keystate[SDL_SCANCODE_S]) {
playerY -= dirY;
playerX -= dirX;
}
if(keystate[SDL_SCANCODE_A]) {
playerY -= dirX;
playerX += dirY;
}
if(keystate[SDL_SCANCODE_D]) {
playerY += dirX;
playerX -= dirY;
}
//rotatez(-ROTSPEED);
playerY -= dirY;//for testing
playerX -= dirX;//for testing
int heightBuffer[RESX] = {[0 ... 959] = RESY};
int playerHeight = 80;//disp[(int)playerX][(int)playerY] + 50;
int dpix = 0;
for( int dDist = 1; dDist < DRAWDISTANCE; dDist+=1) {
for( int pix = -dDist; pix < dDist; pix++) {
int pdpix = dpix;
dpix = (pix/(float)dDist+1) *HRESX;
int sampleX = (int)playerX + dDist*dirX + pix*-dirY;
int sampleY = (int)playerY + dDist*dirY + pix*dirX;
int height = disp[sampleX][sampleY];
int heightOnScreen = ( ((float)playerHeight - height) / dDist * 240 + 240); //alg for persp proj
if(heightOnScreen > 0 && heightOnScreen < RESY) {
for( pdpix; pdpix < dpix; pdpix++) {
if(heightOnScreen < heightBuffer[pdpix]) {
for(int y = heightBuffer[pdpix]; y > heightOnScreen; y-=1) {
pixels[y][pdpix] = col[sampleX][sampleY]; //if I comment out this line, segfault goes away.
}
heightBuffer[pdpix] = heightOnScreen;
}
}
}
}
}
SDL_UpdateTexture(texture, NULL, pixels, RESX * sizeof(Uint32));
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent( renderer );
t2 = SDL_GetTicks();
printf("%ld fps\n", 1000/(t2-t1));
}
SDL_DestroyWindow( window );
SDL_DestroyRenderer( renderer );
SDL_DestroyTexture( texture );
SDL_Quit();
}
i have developed camshift algorithm by watching some tutorials..but unfortunately it didn't track the selected object....here is my code..i am a beginner to opencv and i need help..problem is the rectangle doesn't follow the object to track...
this my code:
bool destroy=false;
CvRect box;
CvRect track_window;
bool drawing_box = false;
cv::Mat imageROI;
IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject = 0, *histimg = 0;
CvHistogram *hist = 0;
int hdims = 16;
float hranges_arr[] = {0,180};
float* hranges = hranges_arr;
int vmin = 10, vmax = 256, smin = 30;
IplImage *image2;
CvScalar hsv2rgb( float hue );
CvConnectedComp track_comp;
CvBox2D track_box;
void draw_box(Mat img, CvRect rect)
{
imageROI= img(cv::Rect(box.x,box.y,box.width,box.height));
cv::rectangle(img, cvPoint(box.x, box.y), cvPoint(box.x+box.width,box.y+box.height),
cvScalar(0,0,255) ,2);
}
CvScalar hsv2rgb( float hue )
{
int rgb[3], p, sector;
static const int sector_data[][3]=
{{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
hue *= 0.033333333333333333333333333333333f;
sector = cvFloor(hue);
p = cvRound(255*(hue - sector));
p ^= sector & 1 ? 255 : 0;
rgb[sector_data[sector][0]] = 255;
rgb[sector_data[sector][1]] = 0;
rgb[sector_data[sector][2]] = p;
return cvScalar(rgb[2], rgb[1], rgb[0],0);
}
void my_mouse_callback( int event, int x, int y, int flags, void* param )
{
IplImage* frame = (IplImage*) param;
switch( event )
{
case CV_EVENT_MOUSEMOVE:
{
if( drawing_box )
{
box.width = x-box.x;
box.height = y-box.y;
}
}
break;
case CV_EVENT_LBUTTONDOWN:
{
drawing_box = true;
box = cvRect( x, y, 0, 0 );
}
break;
case CV_EVENT_LBUTTONUP:
{
drawing_box = false;
if( box.width < 0 )
{
box.x += box.width;
box.width *= -1;
}
if( box.height < 0 )
{
box.y += box.height;
box.height *= -1;
}
draw_box(frame, box);
}
break;
case CV_EVENT_RBUTTONUP:
{
destroy=true;
}
break;
default:
break;
} }
int _tmain(int argc, _TCHAR* argv[])
{
VideoCapture cap(0);
if(!cap.isOpened())
return -1;
Mat image;
Mat frame;
//cv::Mat image= cv::imread("1.jpg");
cap>>image;
if (!image.data)
return 0;
// Display image
cv::namedWindow("Image");
cv::imshow("Image",image);
IplImage* img = new IplImage(image);
cvSmooth(img,img,CV_GAUSSIAN,3,0,0.0,0.0);
IplImage* temp = cvCloneImage(img);
cvSetMouseCallback("Image", my_mouse_callback, (void*) img);
while( 1 )
{
if (destroy)
{
cvDestroyWindow("Image"); break;
}
cvCopyImage(img, temp);
if (drawing_box)
draw_box(temp, box);
cvShowImage("Image", temp);
if (cvWaitKey(15) == 27)
break;
}
cvReleaseImage(&temp);
cvDestroyWindow("Image");
for(;;)
{
int i, bin_w, c;
cap >> frame;
IplImage* frame_ipl = new IplImage(frame);
hsv = cvCreateImage( cvGetSize(frame_ipl), 8, 3 );
image2 = cvCreateImage( cvGetSize(frame_ipl), 8, 3 );
hue = cvCreateImage( cvGetSize(frame_ipl), 8, 1 );
mask = cvCreateImage( cvGetSize(frame_ipl), 8, 1 );
backproject = cvCreateImage( cvGetSize(frame_ipl), 8, 1 );
hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 );
histimg = cvCreateImage( cvSize(320,200), 8, 3 );
cvZero( histimg );
cvCopy( frame_ipl, image2, 0 );
cvCvtColor( image2, hsv, CV_BGR2HSV );
int _vmin = vmin, _vmax = vmax;
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
cvScalar(180,256,MAX(_vmin,_vmax),0), mask );
cvSplit( hsv, hue, 0, 0, 0 );
float max_val = 0.f;
cvSetImageROI( hue, box );
cvSetImageROI( mask, box );
cvCalcHist( &hue, hist, 0, mask );
cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 );
cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 );
cvResetImageROI( hue );
cvResetImageROI( mask );
track_window = box;
cvZero( histimg );
bin_w = histimg->width / hdims;
for( i = 0; i < hdims; i++ )
{
int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );
CvScalar color = hsv2rgb(i*180.f/hdims);
cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
cvPoint((i+1)*bin_w,histimg->height - val),
color, -1, 8, 0 );
}
cvCalcBackProject( &hue, backproject, hist );
cvAnd( backproject, mask, backproject, 0 );
cvCamShift( backproject, track_window, cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ), &track_comp, &track_box );
track_window = track_comp.rect;
cv::rectangle(frame, track_window, cv::Scalar(0,255,0));
cv::namedWindow("result");
cv::imshow("result",frame);
if(waitKey(30) >= 0) break;
}
return 0;
}
but I use the c-api
What might this code be changed to IplImage :
void draw_box(Mat img, CvRect rect)
{
imageROI= img(cv::Rect(box.x,box.y,box.width,box.height));
cv::rectangle(img, cvPoint(box.x, box.y), cvPoint(box.x+box.width,box.y+box.height),
cvScalar(0,0,255) ,2);
}