日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

bmp2gray

發布時間:2025/5/22 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 bmp2gray 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

用MFC很容易把當前屏幕截取,并顯示在自己程序的UI上。以對話框為例,在執行繪制的單元(比如OnPaint)中調用下面這個函數就能做到:

BOOL CSrnShotDlg::GetMyScreen( ?????????????????? CDC *pdc????????????????????????????????????? // 目標DC ) { ?????????????????? CDC dc; ?????????????????? dc.CreateDC("DISPLAY", NULL, NULL, NULL); // 屏幕DC ?????????????????? CRect clientRect; ?????????????????? GetClientRect(clientRect); ????????????????????????????????????????? // 對話框矩形區域 ?????????????????? pdc->BitBlt(0, 0, ??????????????????????????????????????????????????????????? // 起始位置 ???????????????????????????????????? clientRect.Width(),clientRect.Height(),??? // 寬高 ???????????????????????????????????? &dc, ??????????????????????????????????????????????????????????????? // CDC對象 ???????????????????????????????????? 0, 0,??????????????????????????????????????????????????????????????????? // 源位置 ???????????????????????????????????? SRCCOPY?????????????????????????????????????????????????????? // 復制方法 ???????????????????????????????????? ); ?????????????????? dc.DeleteDC();
?????????????????? return TRUE;
}
接下來改造一下,把屏幕截圖先轉換為灰度(Gray Scale)圖,再顯示出來。轉換灰度圖的公式是,對一個RGB值,R、G、B分別是其3色分量,計算: Gray = R * 0.299 + G *0.587 + B * 0.114 然后將Gray分別替換掉原來的3色分量。到這個地方,很自然想到用SetPixel/GetPixel來實現。因為要對DC進行操作,當然就不能直接在上面GetMyScreen里邊的dc直接操作了,為此對GetMyScreen進行一下改造,并且,為了程序的可讀性,增加一個ConvertToGray函數負責轉換(與上面代碼不同的地方用紅色區分):
void ConvertToGray (CDC * pdc) { ?????????????????? for (int xx = 0; xx < clientRect.right ; xx ++) ???????????????????????????????????? for (int yy = 0; yy < clientRect.bottom ; yy ++) ???????????????????????????????????? { ??????????????????????????????????????????????????????? COLORREF crTemp = pdc->GetPixel(xx,yy); ??????????????????????????????????????????????????????? BYTE pixelR = GetRValue(crTemp); ??????????????????????????????????????????????????????? BYTE pixelG = GetGValue(crTemp); ??????????????????????????????????????????????????????? BYTE pixelB = GetBValue(crTemp); ??????????????????????????????????????????????????????? BYTE gray = (BYTE) (pixelR * 0.299 + pixelG * 0.587 +pixelB * 0.114); ??????????????????????????????????????????????????????? pdc->SetPixelV(xx,yy,RGB(gray, gray, gray)); ???????????????????????????????????? } } BOOL CSrnShotDlg::GetMyScreen( ?????????????????? CDC *pdc????????????????????????????????????? // 目標DC ) { ?????????????????? CDC dc; ?????????????????? dc.CreateDC("DISPLAY", NULL, NULL, NULL); // 屏幕DC ?????????????????? CRect clientRect; ?????????????????? GetClientRect(clientRect); ????????????????????????????????????????? // 對話框矩形區域 ?????????????????? CDC????????? *pMemDC = NULL; ?????????????????????????????????? // 兼容DC ?????????????????? pMemDC = new CDC; ?????????????????? if (!pMemDC) ???????????????????????????????????? return FALSE; ?????????????????? pMemDC->CreateCompatibleDC(&dc); ?????????????????? ShowWindow(SW_HIDE); ?????????????????? pMemDC->BitBlt(0, 0, ???????????????????????????????????? clientRect.Width(), clientRect.Height(), ???????????????????????????????????? &dc, 0, 0, SRCCOPY); ?????????????????? ConvertToGray(pMemDC); ?????????????????? pdc->BitBlt(0, 0, ??????????????????????????????????????????????????????????? // 起始位置 ???????????????????????????????????? clientRect.Width(),clientRect.Height(),??? // 寬高 ???????????????????????????????????? pMemDC,??????????????????????????????????????????????????????? // CDC對象 ???????????????????????????????????? 0, 0,??????????????????????????????????????????????????????????????????? // 源位置 ???????????????????????????????????? SRCCOPY?????????????????????????????????????????????????????? // 復制方法 ???????????????????????????????????? ); ?????????????????? pMemDC->DeleteDC(); ?????????????????? delete pMemDC; ?????????????????? dc.DeleteDC(); ?????????????????? return TRUE; }
效果出來了,但是并不完美。實際上我用SetPixelV代替了SetPixel,但顯示的速度還是很慢,CPU使用率也很高。如何提高效率呢?直接改DC上附著的位圖數據似乎是個好辦法。下面就轉而對CBitmap類對象進行操作。 因為是直接截屏,所以需要先用CDC::GetDeviceCaps帶BITSPIXEL參數獲得屏幕色深,因為不同色深的位圖的儲存方式不同。簡要說明一下:16位色位圖,每個象素占2字節;24位色,每個象素占3字節;32位色,每個象素占4字節儲存空間。我們可以用CBitmap::GetBitmapBits函數來獲得位圖數據,這其實是一個BYTE數組。這個數組的結構,最簡單的是24位色的情況。前面說過了每個象素占3個字節,按數組下標從低到高分別是B、G、R這3色分量,而32位色的情況跟24位色類似,4個字節只不過多了一個alpha值。下面就是處理24位色深的ConvertToGray24。
#define BITS24??????? (int)(1024 * 768 * 3) void ConvertToGray24(CBitmap *pBmp) { ?????????????????? LPBYTE lpbits = NULL; ?????????????????? lpbits = new BYTE[BITS24]; ?????????????????? if (!lpbits) ???????????????????????????????????? return; ?????????????????? ZeroMemory(lpbits, BITS24); ?????????????????? pBmp->GetBitmapBits(BITS24, lpbits); ?????????????????? for (int index = 0, j = 0, k = 0; index < BITS24; index ++) ?????????????????? { ???????????????????????????????????? lpbits[index] = (BYTE)(0.114 * lpbits[index]); ???????????????????????????????????? j = index + 1; k = index + 2; ???????????????????????????????????? lpbits[j] = (BYTE)(0.587 * lpbits[j]); ???????????????????????????????????? lpbits[k] = (BYTE)(0.299 * lpbits[k]); ???????????????????????????????????? lpbits[index] += lpbits[j] + lpbits[k]; ???????????????????????????????????? lpbits[j] = lpbits[index]; ???????????????????????????????????? lpbits[k] = lpbits[index]; ???????????????????????????????????? index = k; ?????????????????? } ?????????????????? pBmp->SetBitmapBits(BITS24, lpbits); ?????????????????? delete [] lpbits; }
當GetDeviceCaps(BITSPIXEL)返回16的時候,又有兩種情況:16位色和15位色。16位色的情況下,位圖數組使用2字節保存數據,其中從高位往低位分別是B、G、R這3色分量按位5:6:5占用。需要用位操作來獲得每個分量的色值:
#define GetRValueX(rgb)????? ((BYTE)(rgb) & 0x1f) #define GetGValueX(rgb)????? ((BYTE)(((rgb) & 0x07E0) >> 5)) #define GetBValueX(rgb)????? ((BYTE)(((rgb) & 0xF800) >> 11)) #define RGBX(r,g,b) \ ????????? ((WORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<5))|(((WORD)(BYTE)(b))<<11)))
要注意的是因為綠色分量占用了6bit,其儲存精度是其它兩個分量的2倍,所以在進行后繼的計算的時候公式的因數會有所改變。(另外,使用15位色的適配器比較少,其儲存規則也是占用2字節,但是最高位無意義,其余15位按5:5:5分配,這里不詳細討論了。)
#define BITS16??????? (int)(1024 * 768 * 2) void ConvertToGray16(CBitmap *pBmp) { ?????????????????? LPBYTE lpbits = NULL; ?????????????????? WORD *wBits; ?????????????????? lpbits = new BYTE[BITS16]; ?????????????????? if (!lpbits) ???????????????????????????????????? return; ?????????????????? ZeroMemory(lpDibits, BITS16); ?????????????????? pBmp->GetBitmapBits(BITS16, lpbits); ?????????????????? for (int index = 0, j = 0, k = 0; index < BITS16; index ++) ?????????????????? { ???????????????????????????????????? wBits = (WORD *)(lpbits + index); ???????????????????????????????????? BYTE pixelR = GetRValueX(*wBits) * 2; ???????????????????????????????????? BYTE pixelG = GetGValueX(*wBits) ;???? // 注意系數 ???????????????????????????????????? BYTE pixelB = GetBValueX(*wBits) * 2; ???????????????????????????????????? BYTE gray =(BYTE) (pixelR * 0.299 + pixelG * 0.587 +pixelB * 0.114); ???????????????????????????????????? *wBits = RGBX(gray / (BYTE)2, gray, gray / (BYTE)2); ???????????????????????????????????? index ++; ?????????????????? } ?????????????????? pBmp->SetBitmapBits(BITS16, lpbits); ?????????????????? delete [] lpbits; }
最后,第三次改造GetMyScreen:
BOOL CSrnShotDlg::GetMyScreen( ?????????????????? CDC *pdc????????????????????????????????????? // 目標DC ) { ?????????????????? CDC dc; ?????????????????? dc.CreateDC("DISPLAY", NULL, NULL, NULL); // 屏幕DC ?????????????????? CRect clientRect; ?????????????????? GetClientRect(clientRect); ????????????????????????????????????????? // 對話框矩形區域 ?????????????????? CDC????????? *pMemDC = NULL; ?????????????????????????????????? // 兼容DC ?????????????????? CBitmap *pBmp = NULL; ????????????????????????????????????????? // 兼容位圖 ?????????????????? pMemDC = new CDC; ?????????????????? if (!pMemDC) ???????????????????????????????????? return FALSE; ?????????????????? pMemDC->CreateCompatibleDC(&dc); ?????????????????? ?????????????????? pBmp = new CBitmap; ?????????????????? if (!pBmp) ?????????????????? { ???????????????????????????????????? pMemDC->DeleteDC(); ???????????????????????????????????? delete pMemDC; ???????????????????????????????????? return FALSE; ?????????????????? } ?????????????????? pBmp->CreateCompatibleBitmap(&dc, clientRect.Width(),clientRect.Height()); ?????????????????? pMemDC->SelectObject(pBmp); ?????????????????? ShowWindow(SW_HIDE); ?????????????????? pMemDC->BitBlt(0, 0, ???????????????????????????????????? clientRect.Width(), clientRect.Height(), ???????????????????????????????????? &dc, 0, 0, SRCCOPY); ?????????????????? switch(pMemDC->GetDeviceCaps(BITSPIXEL)) ?????????????????? { ?????????????????? case: 16 ???????????????????????????????????? ConvertToGray16(pBmp); ???????????????????????????????????? break; ?????????????????? case: 24 ???????????????????????????????????? ConvertToGray24(pBmp); ???????????????????????????????????? break; ?????????????????? case: 32 ???????????????????????????????????? ConvertToGray32(pBmp); ???????????????????????? //未給出 ???????????????????????????????????? break; ?????????????????? default: ???????????????????????????????????? pBmp->DeleteObject(); ???????????????????????????????????? pMemDC->DeleteDC(); ???????????????????????????????????? delete pBmp; ???????????????????????????????????? delete pMemDC; ???????????????????????????????????? dc.DeleteDC(); ???????????????????????????????????? return FALSE; ?????????????????? } ?????????????????? pdc->BitBlt(0, 0, ??????????????????????????????????????????????????????????? // 起始位置 ???????????????????????????????????? clientRect.Width(),clientRect.Height(),??? // 寬高 ???????????????????????????????????? pMemDC, ????????????????????????????????????????????????????? // CDC對象 ???????????????????????????????????? 0, 0,?????????????????????????????? ???????????????????????????????????? // 源位置 ???????????????????????????????????? SRCCOPY?????????????????????????????????????????????????????? // 復制方法 ???????????????????????????????????? ); ?????????????????? pBmp->DeleteObject(); ?????????????????? pMemDC->DeleteDC(); ?????????????????? delete pBmp; ?????????????????? delete pMemDC; ?????????????????? dc.DeleteDC(); ?????????????????? return TRUE; }

----------------------------------------------------

附文件讀取

ConvertBmp24ToBmp256
{
?FILE *fp = fopen("test.bmp","rb");
?if(!fp)return;

?BITMAPFILEHEADER hdr;
?
?fread(&hdr,1,sizeof(hdr),fp);

?if(!(((hdr.bfType & 0xff) == 'B') &&? ((hdr.bfType >> 8) == 'M')))
?{
??fclose(fp);
??return;
?}

?BITMAPINFOHEADER bih;

?fread(&bih,1,sizeof(bih),fp);

?if(bih.biBitCount != 24 || bih.biCompression != 0)
?{
??fclose(fp);
??return;
?}

?unsigned char *pBuf = new unsigned char[bih.biSizeImage];

?fread(pBuf,bih.biSizeImage,sizeof(unsigned char),fp);


?FILE *out = fopen("testout.bmp","wb");
?if(!out)
?{
??delete []pBuf;
??fclose(fp);
??return;
?}

?unsigned char *pOutBuf = new unsigned char[bih.biWidth * bih.biHeight];
?unsigned char *tmp = pBuf;
?unsigned char *tmp2 = pOutBuf;
?for(unsigned int i = 0; i < bih.biWidth * bih.biHeight;i++)
?{
??tmp2[i] = (unsigned char)((*tmp) * .114 + *(tmp + 1) * .587 + *(tmp + 2) * .299);
??tmp += 3;
?}

?RGBQUAD q[256];
?for( i = 0; i < 256; i++)
?{
??q[i].rgbRed = q[i].rgbGreen = q[i].rgbBlue = i;
??q[i].rgbReserved = 0;
?}

?bih.biBitCount = 8;
?bih.biSizeImage = bih.biWidth * bih.biHeight;

?hdr.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
??+ sizeof(q) + bih.biSizeImage;
?hdr.bfOffBits += sizeof(q);

?fwrite(&hdr,1,sizeof(hdr),out);
?fwrite(&bih,1,sizeof(bih),out);
?fwrite(q,256,sizeof(RGBQUAD),out);
?fwrite(pOutBuf,bih.biSizeImage,sizeof(unsigned char),out);

?delete []pOutBuf;
?fclose(out);
?delete []pBuf;
?fclose(fp);
}?

轉載于:https://www.cnblogs.com/swordzj/archive/2007/04/12/2034771.html

總結

以上是生活随笔為你收集整理的bmp2gray的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。