邊緣對應影像局部亮度劇烈變化區域。對數位影像,一階微分近似為差分,梯度幅值表示邊緣強度。常用算子:
G[i,j] = |f[i,j] - f[i+1,j+1]| + |f[i+1,j] - f[i,j+1]|
對角線方向敏感,計算快但雜訊敏感。
水平梯度:
Δx = f(x-1,y+1) + 2f(x,y+1) + f(x+1,y+1) - f(x-1,y-1) - 2f(x,y-1) - f(x+1,y-1)
垂直梯度:
Δy = f(x-1,y-1) + 2f(x-1,y) + f(x-1,y+1) - f(x+1,y-1) - 2f(x+1,y) - f(x+1,y+1)
梯度幅值:G = |Δx| + |Δy| (近似 L1 範數,避免開根號)。
G[i,j] = |f[i+1,j] + f[i-1,j] + f[i,j+1] + f[i,j-1] - 4f[i,j]|
零交越點對應邊緣,對雜訊極敏感,通常配合高斯平滑 (LoG)。
假設 CDibView 已取得灰階影像指標 hData、寬高 biWidth/biHeight、位元組寬 WIDTHBYTES。
void CDibView::OnMenuSobel()
{
CDibDoc* pDoc = GetDocument();
HDIB hDib = pDoc->m_hDIB;
LPBITMAPINFOHEADER lpBi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
BYTE* hData = (BYTE*)lpBi + lpBi->biSize + 256*sizeof(RGBQUAD);
HANDLE hBuf = GlobalAlloc(GMEM_FIXED, WIDTHBYTES(lpBi->biWidth*8) * lpBi->biHeight);
BYTE* data = (BYTE*)GlobalLock(hBuf);
BeginWaitCursor();
for (int y=1; y < lpBi->biHeight-1; y++)
for (int x=1; x < lpBi->biWidth-1; x++)
{
int idx = y * WIDTHBYTES(lpBi->biWidth*8) + x;
int idxUp = idx - WIDTHBYTES(lpBi->biWidth*8);
int idxDown = idx + WIDTHBYTES(lpBi->biWidth*8);
// Δx (水平)
int gx = (hData[idxUp+1] + 2*hData[idx+1] + hData[idxDown+1])
- (hData[idxUp-1] + 2*hData[idx-1] + hData[idxDown-1]);
// Δy (垂直)
int gy = (hData[idxUp-1] + 2*hData[idxUp] + hData[idxUp+1])
- (hData[idxDown-1] + 2*hData[idxDown] + hData[idxDown+1]);
int g = abs(gx) + abs(gy);
if (g > 255) g = 255;
data[idx] = (BYTE)g;
}
// 複製回原緩衝區並更新視圖
memcpy(hData, data, WIDTHBYTES(lpBi->biWidth*8) * lpBi->biHeight);
GlobalUnlock(hBuf); GlobalFree(hBuf);
GlobalUnlock(hDib);
EndWaitCursor();
Invalidate(TRUE);
}
// Roberts (邊界需特殊處理)
int g = abs(hData[idx] - hData[idx+W+1]) + abs(hData[idx+1] - hData[idx+W]);
// Laplacian
int g = abs(hData[idx-W] + hData[idx+W] + hData[idx-1] + hData[idx+1] - 4*hData[idx]);