工程應用中經常要遇到需要把彩色圖像到灰度圖像的變換的問題,采集卡過來的圖像為彩色圖像,為加快處理速度,要把彩色圖像轉換為黑白圖象,這個問題比較好解決,一般情況下彩色圖像每個像素用三個字節表示,每個字節對應著R、G、B分量的亮度(紅、綠、藍),轉換後的黑白圖像的一個像素用一個字節表示該點的灰度值,它的值在0~255之間,數值越大,該點越白,既越亮,越小則越黑。轉換公式為Gray(i,j)=0.11*R(i,j)+0.59*G(i,j)+0.3*B(i,j),其中Gray(i,j)為轉換後的黑白圖像在(i,j)點處的灰度值,我們可以觀察該式,其中綠色所占的比重最大,所以轉換時可以直接使用G值作為轉換後的灰度。
至於灰度圖像轉換為彩色圖像,技術上稱為灰度圖像的偽彩色處理,這是一種視覺效果明顯而技術又不是很復雜的圖像增強技術。灰度圖像中,如果相鄰像素點的灰度相差不大,但包含了豐富的信息的話,人眼則無法從圖像中提取相應的信息,因為人眼分辨灰度的能力很差,一般只有幾十個數量級,但是人眼對彩色信號的分辨率卻很強,這樣將黑白圖像轉換為彩色圖像人眼可以提取更多的信息量。在轉換過程中,經常采用的技術是灰度級-彩色變換,意思就是對黑白圖像上的每一個像素點,取得該點的灰度值並送入三個通道經過實施不同的變換,產生相應的R、G、B的亮度值,即所求彩色圖像對應像素點的彩色值,具體變換公式很多,我采用的是最常用的一種,變換曲線圖如下:
上圖中,三個圖分別代表了三個變換通道,R、G、B指的是變換後對應點的R、G、B分量值,L指的是各個分量的最大值為255,G(x,y)為相應點的灰度值。理論上就這些,下面是我用VC實現的源代碼,圖一為我的灰度位圖,圖二為偽彩色處理後的結果圖。我這個實現函數中是如何得到灰度位圖的數據的就不多講了,有興趣的朋友可參考我在天極網上九月十號發表的《VC灰度位圖處理》一文,那裡應該講的很清楚了。需要讀者注意的是彩色圖像中每個象素中的三個字節分別代表的分量,第一個字節為B,第二個為G值、最後一個為R值,這個順序不要搞錯了。代碼實現如下:
void CDibVIEw::OnMenuchange() file://圖像轉換實現函數
{
// TODO: Add your command handler code here
HANDLE data1handle;
LPBITMAPINFOHEADER lpBi;
BITMAPINFO *m_pBMI;
CDibDoc *pDoc=GetDocument();
HDIB hdib;
unsigned char *hData;
unsigned char *data;
hdib=pDoc->GetHDIB();//得到位圖數據的句柄,其中包含圖像信息頭
BeginWaitCursor();
lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);
hData=(unsigned char*)FindDIBBits((LPSTR)lpBi);
m_pBMI=new BITMAPINFO;//生成彩色圖像的信息頭
m_pBMI->bmiHeader.biBitCount=24;
m_pBMI->bmiHeader.biClrImportant=0;
m_pBMI->bmiHeader.biClrUsed=0;
m_pBMI->bmiHeader.biCompression=BI_RGB;
m_pBMI->bmiHeader.biHeight=lpBi->biHeight;
m_pBMI->bmiHeader.biWidth=lpBi->biWidth;
m_pBMI->bmiHeader.biPlanes=1;
m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
m_pBMI->bmiHeader.biXPelsPerMeter=0;
m_pBMI->bmiHeader.biYPelsPerMeter=0;
m_pBMI->bmiHeader.biSizeImage=WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight*3;
file://data=hData;
int R,G,B,i,j;
data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight*3);
file://生成存儲彩色圖象數據的緩沖區
data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);
for(i=0;ibiHeight;i++)//實現灰度到彩色變換
for(j=0;jbiWidth*8);j++)
{
if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=64)
{R=0;
G=(int)4*(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j));
B=255;
}
if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)>64
&& *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=128)
{R=0;
G=255;
B=(int)4*(128-*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j));
}
if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)>128
&& *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=192)
{R=(int)4*(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)-128);
G=255;
B=0;
}
if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)>192
&& *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=255)
{R=255;
G=(int)4*(255-*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j));
B=0;
}
file://將生成的R、G、B分量存入目標緩沖區
*(data+i*WIDTHBYTES(lpBi->biWidth*8)*3+j*3)=B;
*(data+i*WIDTHBYTES(lpBi->biWidth*8)*3+j*3+1)=G;
*(data+i*WIDTHBYTES(lpBi->biWidth*8)*3+j*3+2)=R;
}
GlobalUnlock((HGLOBAL)hdib);
GlobalUnlock(data1handle);
EndWaitCursor();
CClIEntDC pDC(this);
file://顯示真彩色圖像
StretchDIBits(pDC.GetSafeHdc(),0,0,lpBi->biWidth,lpBi->biHeight,0,0,
lpBi->biWidth, lpBi->biHeight,data,m_pBMI,DIB_RGB_COLORS,
SRCCOPY);
delete m_pBMI;
}
圖 一
圖 二
數字圖像處理技術博大精深,我真誠的希望和廣大朋友探討