電視劇片頭常見的「浮雕」與「雕刻」效果,實為數字圖像處理算法:浮雕讓前景凸出背景,雕刻讓前景凹陷背景。兩者均基於鄰域像素差值運算,配合偏移常量保持亮度。本文以標準 Lena 灰度圖為例,給出算法詳解、效果對比與 VC++ 核心實現代碼。
對每個像素 (i, j),計算其與左上鄰居 (i-1, j-1) 的差值,加 128 保持中性灰:
Output(i,j) = Input(i,j) - Input(i-1,j-1) + 128
結果裁剪至 [0, 255]。關鍵: 為避免使用已修改的像素,必須從右下角向左上角逆序處理。
void CDibView::OnFDImage() // 產生浮雕效果
{
HANDLE data1handle;
LPBITMAPINFOHEADER lpBi;
CDibDoc *pDoc = GetDocument();
HDIB hdib = pDoc->GetHDIB();
BeginWaitCursor();
lpBi = (LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);
unsigned char *hData = (unsigned char*)FindDIBBits((LPSTR)lpBi);
pDoc->SetModifiedFlag(TRUE);
// 分配緩衝區存放處理後數據
data1handle = GlobalAlloc(GMEM_SHARE, WIDTHBYTES(lpBi->biWidth * 8) * lpBi->biHeight);
unsigned char *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; j < lpBi->biHeight; j++)
for (i = 0; i < lpBi->biWidth; 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); // 刷新顯示
}
與浮雕相反:取當前像素與右下鄰居差值加 128:
Output(i,j) = Input(i,j) - Input(i+1,j+1) + 128
同樣裁剪至 [0, 255]。處理順序:從左上向右下,避免使用已修改像素。
void CDibView::OnDKImage() // 產生雕刻效果
{
// ... 相同初始化代碼 ...
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;
}
// ... 相同寫回與清理代碼 ...
Invalidate(TRUE);
}
掌握這兩個基礎算法,即掌握了數字圖像處理中空間域增強的核心技巧之一。