經常看電視的朋友們不知注意到沒有,最近的電視連續劇在每集片頭或片尾部分都有顯示一些特殊效果的圖像,比如前一陣子中央一套放的《長征》、目前中央八套正在播放的《康熙王朝》,這些特效稱為"圖像的浮雕效果"和"圖像的雕刻效果",經過這些特效處理後的圖像增強了觀眾們的視覺效果,它們看上去仿佛是使用3D技術作的,這也是為什麼這種技術那麼流行的原因吧。其實,我們完全可以用一些簡單的數字圖像處理算法來實現這些看似復雜高深的顯示效果。我們手頭上的一些關於利用VC開發數字圖像資料大都是講解如何控制圖像的每一行或每一列像素的顯示時間或順序來實現一些簡單的圖像顯示效果,涉及到圖像算法的文章很少,本文針對上述的這兩種圖像特效處理技術並加以引伸,講解了一些實現圖像特效算法,以一個標准的Lena灰度圖像為原圖,給出了處理後的效果圖,同時給出了VC開發平台上的部分實現源代碼。
1."浮雕"圖像
"浮雕"圖象效果是指圖像的前景前向凸出背景。所謂的"浮雕"概念是指標繪圖像上的一個像素和它左上方的那個像素之間差值的一種處理過程,為了使圖像保持一定的亮度並呈現灰色,我在處理過程中為這個差值加了一個數值為128的常量。需要讀者注意的是,當設置一個像素值的時候,它和它左上方的像素都要被用到,為了避免用到已經設置過的像素,應該從圖像的右下方的像素開始處理,下面是實現的源代碼:
void CDibVIEw::OnFDImage() //產生"浮雕"效果圖函數
{
HANDLE data1handle;
LPBITMAPINFOHEADER lpBi;
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);
pDoc->SetModifIEdFlag(TRUE);
data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight);
//聲明一個緩沖區用來暫存處理後的圖像數據
data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);
AfxGetApp()->BeginWaitCursor();
int i,j,buf;
for( i=lpBi->biHeight; i>=2; i--)
for( j=lpBi->biWidth; j>=2; j--)
{
//"浮雕"處理
buf=*(hData+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)-*(hData+(lpBi->biHeight-i+1)*WIDTHBYTES(lpBi->biWidth*8)+j-1)+128;
if(buf>255) buf=255;
if(buf<0)buf=0;
*(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf;
}
for( j=0; jbiHeight; j++)
for( i=0; ibiWidth; i++)
//重新寫回原始圖像的數據緩沖區
*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j);
AfxGetApp()->EndWaitCursor();
GlobalUnlock((HGLOBAL)hdib);
GlobalUnlock(data1handle);
EndWaitCursor();
Invalidate(TRUE);//顯示圖像
}
2."雕刻"圖像
上面講述了通過求一個像素和它左上方像素之間的差值並加上一個常數的方法生成"浮雕"效果的灰度圖像,"雕刻"圖像與之相反,它是通過取一個像素和它右下方的像素之間的差值並加上一個常數,這裡我也取128,經過這樣處理,就可以得到"雕刻"圖像,這時候圖像的前景凹陷進背景之中。同樣需要讀者注意的是為了避免重復使用處理過的圖像像素,處理圖像時要從圖像的左上方的像素開始處理。實現代碼如下:
void CDibVIEw::OnDKImage()
{
// TODO: Add your command handler code here
HANDLE data1handle;
LPBITMAPINFOHEADER lpBi;
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);
pDoc->SetModifIEdFlag(TRUE);
data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight);
data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);
AfxGetApp()->BeginWaitCursor();
int i,j,buf;
//圖像的"雕刻"處理
for( i=0;i<=lpBi->biHeight-2; i++)
for( j=0;j<=lpBi->biWidth-2; j++)
{
buf=*(hData+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)-*(hData+(lpBi->biHeight-i-1)*WIDTHBYTES(lpBi->biWidth*8)+j+1)+128;
if(buf>255) buf=255;
if(buf<0)buf=0;
*(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf;
}
for( j=0; jbiHeight; j++)
for( i=0; ibiWidth; i++)
//重新將處理後的圖像數據寫入原始的圖像緩沖區內
*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j);
AfxGetApp()->EndWaitCursor();
GlobalUnlock((HGLOBAL)hdib);
GlobalUnlock(data1handle);
EndWaitCursor();
Invalidate(TRUE);
}