Converting Color Bitmap to Grayscale in C++
Need to convert a color bitmap to a grey scale. Here is the approach:
HDC hdcWindow = GetDC(hWnd);
HBITMAP hDIBBitmap;
{
// Create a compatible DC which is used in a BitBlt from the window DC
HDC hdcMemDC = CreateCompatibleDC(hdcWindow);
SelectObject(hdcMemDC, bmHatch);
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = bm.bmWidth;
bmi.bmiHeader.biHeight = bm.bmHeight; // top-down
bmi.bmiHeader.biPlanes = bm.bmPlanes;
bmi.bmiHeader.biBitCount = bm.bmBitsPixel;
UINT* pBits;
HBITMAP hDIBBitmap = CreateDIBSection(hdcMemDC, &bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, NULL);
for (int i = 0; i < bm.bmWidth; i++) {
for (int j = 0; j < bm.bmHeight; j++) {
UINT val = pBits[i + j * bm.bmWidth];
if (val != 0)
{
COLORREF clr = val;
UINT newVal = (GetRValue(clr) + GetBValue(clr) + GetGValue(clr)) / 3;
pBits[i + j * bm.bmWidth] = newVal;
}
}
}
SelectObject(hdcMemDC, hDIBBitmap);
// draw content of memory bitmap in the window
BitBlt(hdcWindow, 0, 0, bm.bmWidth, bm.bmHeight, hdcMemDC, 0, 0, SRCCOPY);
DeleteObject(hDIBBitmap);
DeleteDC(hdcMemDC);
}
ReleaseDC(hWnd, hdcWindow);
In the above code sample, the input bitmap is given by bm which is a Bitmap instance.
Created a compatible DC. Loaded the bitmap into using the selectObject statement. Then wanted to change the bits by creating the DIB section for traversing the bitmap values. After changing the values, the hDIBBitmap is selected and then finally drawing using the BitBlt function.
When I comment out the following line, I can see the original bitmap rendered correctly: SelectObject(hdcMemDC, hDIBBitmap);
What I observed was the pBits is always 0 and hence the transformed gray scale image is not being rendered and instead getting a black picture.
Please advise on what is wrong with this approach.
CreateDIBSection
is creating a blank bitmap with that usage. None of the bits from the original bitmap are used. If you paint it you get a black bitmap.
If you comment out SelectObject(hdcMemDC, hDIBBitmap)
then this new hDIBBitmap
is ignored as well. You print the original bitmap which was selected in device context earlier: SelectObject(hdcMemDC, bmHatch)
To convert HBITMAP
to gray scale use the following code. Note this will not work for palette bitmaps.
Converting 24-bit or 32-bit HBITMAP
to grayscale:
void grayscale(HBITMAP hbitmap)
{
BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm);
if(bm.bmBitsPixel < 24)
{
DebugBreak();
return;
}
HDC hdc = GetDC(HWND_DESKTOP);
DWORD size = ((bm.bmWidth * bm.bmBitsPixel + 31) / 32) * 4 * bm.bmHeight;
BITMAPINFO bmi
{sizeof(BITMAPINFOHEADER),bm.bmWidth,bm.bmHeight,1,bm.bmBitsPixel,BI_RGB,size};
int stride = bm.bmWidth + (bm.bmWidth * bm.bmBitsPixel / 8) % 4;
BYTE *bits = new BYTE[size];
GetDIBits(hdc, hbitmap, 0, bm.bmHeight, bits, &bmi, DIB_RGB_COLORS);
for(int y = 0; y < bm.bmHeight; y++) {
for(int x = 0; x < stride; x++) {
int i = (x + y * stride) * bm.bmBitsPixel / 8;
BYTE gray = BYTE(0.1 * bits[i+0] + 0.6 * bits[i+1] + 0.3 * bits[i+2]);
bits[i+0] = bits[i+1] = bits[i+2] = gray;
}
}
SetDIBits(hdc, hbitmap, 0, bm.bmHeight, bits, &bmi, DIB_RGB_COLORS);
ReleaseDC(HWND_DESKTOP, hdc);
delete[]bits;
}
Usage
//convert to grayscale
//this should be called once
grayscale(hbitmap);
//paint image
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP oldbmp = SelectObject(memdc, hbitmap);
BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm);
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);
...
链接地址: http://www.djcxy.com/p/50296.html
上一篇: 调整大小时在窗口中绘制未涂漆的边框
下一篇: 在C ++中将彩色位图转换为灰度