Back
PQCHub

銳化與邊緣偵測

學習銳化與邊緣偵測,透過卷積核強化細節或提取輪廓,看見影像背後的神奇演算法。


1. 銳化概念

銳化 (Sharpening) 的目的在於強化影像中快速變化的像素,也就是增加邊緣或細節的對比。

1.1 理論基礎

  • 銳化通常使用 高通濾波 (High-pass Filter)
  • 一個常見的卷積核範例:
[  0, -1,  0 ]
[ -1,  5, -1 ]
[  0, -1,  0 ]

說明:

  1. 中間值 5:保留原始像素的主要亮度
  2. 四周的 -1:減去鄰近像素的平均值
  3. 結果:像素與鄰近像素差異越大,亮度增強,形成銳化效果

1.2 卷積計算方法

對每個像素 (x, y)

newPixel = sum( kernel[i][j] * pixel(x+i, y+j) )
  • i,j 為卷積核的座標偏移。 例如3x3卷積核 i = -1 ~ +1, j = -1 ~ +1
  • 對每個通道 (R, G, B) 分別計算
  • 計算後需要 裁剪至 0~255,避免溢出

1.3 注意事項

  1. 邊界像素的處理:

    • 可以使用 複製邊界忽略邊界
  2. 對 BMP 24-bit RGB 的操作:

    • 每個像素三個通道分別卷積
    • 可沿用前面灰階或模糊範例的座標與索引計算方法
  3. 與前面模糊不同:

    • 這次卷積核包含負值,結果可能增亮或增暗,必須注意裁剪

2. JavaScript 自製程式 — 銳化

使用前面自製的 BmpImage 類別與convolve,可以對每個像素進行卷積運算,實作銳化效果。

2.1 使用範例

import BmpImage from './BmpImage.js';
import convolve from './convolve.js';

const img = BmpImage.load("input.bmp");

// 銳化卷積核
const sharpenKernel = [
    [ 0, -1,  0 ],
    [-1,  5, -1 ],
    [ 0, -1,  0 ]
];

// 執行銳化
const sharpened = convolve(img, sharpenKernel);

// 儲存結果
sharpened.save("output_sharpen.bmp");

console.log("銳化完成!");

2.2 說明

  1. convolve 函式會對每個像素套用卷積核
  2. 邊界像素使用 || { r:0,g:0,b:0 } 處理,避免溢出
  3. 計算後裁剪值到 0~255,保持有效 RGB 範圍
  4. 使用 BmpImage.create 建立新的影像,避免直接覆蓋原始影像

3. 邊緣偵測 — Sobel 卷積

在影像處理中,邊緣偵測是非常重要的一環。它可以找出圖像中亮度急劇變化的位置,這些位置通常是物體的輪廓。Sobel 邊緣偵測是一種經典方法,利用 卷積 計算圖像在水平方向和垂直方向的梯度。

3.1 Sobel 原理

Sobel 邊緣偵測透過兩個卷積核分別測量水平與垂直方向的亮度變化:

  • Gx(水平梯度核)

\begin{align} \begin{bmatrix} -1 & 0 & 1\\ -2 & 0 & 2\\ -1 & 0 & 1 \end{bmatrix} \end{align}

  • Gy(垂直梯度核)

\begin{align} \begin{bmatrix} -1 & -2 & -1\\ 0 & 0 & 0\\ 1 & 2 & 1 \end{bmatrix} \end{align}

對每個像素計算:

\begin{align} G = \sqrt{G_x^2 + G_y^2} \end{align}

其中 $G$ 即為邊緣強度。通常會將其映射到 0~255 作為灰階值。

直觀理解:

  • Gx 核會強調左右亮度變化
  • Gy 核會強調上下亮度變化
  • 綜合兩個方向後可以獲得完整的邊緣資訊

4.2 JavaScript 自製卷積實作

function sobelEdgeDetection(img) {
    const width = img.width;
    const height = img.height;
    const result = BmpImage.create(width, height);

    const Gx = [
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ];

    const Gy = [
        [-1, -2, -1],
        [0, 0, 0],
        [1, 2, 1]
    ];

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            let gx = 0, gy = 0;

            for (let ky = 0; ky < 3; ky++) {
                for (let kx = 0; kx < 3; kx++) {
                    const px = x + kx - 1;
                    const py = y + ky - 1;
                    const pixel = img.getPixel(px, py) || { r: 0, g: 0, b: 0 };

                    // 先轉灰階加權法
                    const gray = 0.299 * pixel.r + 0.587 * pixel.g + 0.114 * pixel.b;

                    gx += gray * Gx[ky][kx];
                    gy += gray * Gy[ky][kx];
                }
            }

            // 邊緣強度
            let magnitude = Math.sqrt(gx*gx + gy*gy);
            magnitude = Math.min(255, Math.round(magnitude));

            result.setPixel(x, y, magnitude, magnitude, magnitude);
        }
    }

    return result;
}

4.3 使用範例

import BmpImage from './BmpImage.js';

const img = BmpImage.load("input.bmp");
const edgeImg = sobelEdgeDetection(img);
edgeImg.save("output_edge.bmp");

console.log("Sobel 邊緣偵測完成!");

4.4 詳細解說

  1. 灰階轉換

    • Sobel 計算的是亮度變化,所以先將彩色像素轉為灰階。
    • 使用 加權平均法Gray = 0.299*R + 0.587*G + 0.114*B,模擬人眼對色彩敏感度。
  2. 卷積運算

    • 對每個像素以 3×3 卷積核掃描
    • Gx 與 Gy 分別計算水平方向與垂直方向梯度
  3. 邊緣強度計算

    • 使用勾股定理:sqrt(Gx^2 + Gy^2)
    • 將結果裁剪到 0~255
  4. 結果影像

    • 生成灰階影像,亮的部分即為邊緣
    • 可直接保存為 BMP 觀察效果

小結: Sobel 卷積將卷積與灰階概念結合,不僅可偵測邊緣,還可作為後續影像處理演算法的基礎,如輪廓辨識、物體檢測或馬賽克處理前的區域識別。

SNPQ © 2025