[Python] 圖像處理 – Outline 001 – Edge Detection

【前言】

在我自製「畫家小工具」該過程中,圖片轉線稿是最重要的功能,而生活中在圖像編輯時,人們也常常拓寬邊線形成如貼紙的效果。除上述以外,邊線也是種方便我們尋找物體與看出圖片架構的方式。那我們能透過那些方法找到邊線並加以利用呢?

【預計內容】

  1. Thresholding
  2. Canny Algorithm
  3. Sobel Operator
  4. Laplacian
  5. 程式碼提供

【主要內容】

1. Thresholding

Thresholding 故其名,是透過設定像素值的區間保留區塊。這種方法十分不穩定,並且本質上來說不算邊線偵測的方法,但時常使用的前處理方式。舉個例,今天有張黑白斑點的背景,那轉為灰階後只選擇保留中間的數值,我們就能夠減少背景斑點的影響,生成更乾淨的線稿或遮罩(mask)。當然,若前景角色的衣物有深淺色的話也很容易被刪掉,因此去除背景更是一件複雜但重要的功能。

2. Canny Algorithm

坎尼算子先透過高斯模糊進行降噪,經由 Thresholding 與亮度梯度進行比對,找出可能為邊線的部分。那要注意的一點是,你能夠透過高斯模糊將線條簡單化,但模糊效果太強則容易導致找不到邊線,最終回傳全黑的遮罩。

* 右圖先額外經過 (15, 15) 的高斯模糊

3. Sobel Operator

索伯算子有趣的點是,擁有橫向與縱向的捲積,最後再合併起來,從而帶有微小的方向變化。亦是透過梯度的變化來判斷是否為邊線。那在 opencv 中,可以透過 sobel() 方法的 ksize 調整捲積大小,當 ksize 越大則會得到更模糊的結果。

* 左右之 ksize 分別為 3 與 5

4. Laplacian

拉普拉斯算子亦是透過捲積,透過二次微分偵測黑白的急遽色差,之後透過 Zero-Crossing,即可辨別是否為邊緣。同樣,在 opencv 的 Laplacian() 透過 ksize 調整捲積大小,當 ksize 越大會得到更模糊的效果。

* 左右之 ksize 分別為 3 與 5

5. 程式碼提供

Python
import cv2
import numpy as np
import matplotlib.pyplot as plt

# Read the image
image = cv2.imread('demo.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Apply Canny edge detection
edges_canny = cv2.Canny(gray, 50, 150)

# Apply Sobel operator
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
edges_sobel = cv2.magnitude(sobel_x, sobel_y)
edges_sobel = np.uint8(edges_sobel)

# Apply Laplacian edge detection
laplacian = cv2.Laplacian(gray, cv2.CV_64F, ksize=3)
edges_laplacian = np.uint8(np.absolute(laplacian))

# Apply thresholding
_, thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)

# Plotting
plt.figure(figsize=(12, 10))

# Original Image
plt.subplot(2, 3, 1)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Original')
plt.axis('off')

# Grayscale Image
plt.subplot(2, 3, 2)
plt.imshow(gray, cmap='gray')
plt.title('Grayscale')
plt.axis('off')

# Thresholding
plt.subplot(2, 3, 3)
plt.imshow(thresh, cmap='gray')
plt.title('Thresholding')
plt.axis('off')

# Canny Edge Detection
plt.subplot(2, 3, 4)
plt.imshow(edges_canny, cmap='gray')
plt.title('Canny Edge Detection')
plt.axis('off')

# Sobel Edge Detection
plt.subplot(2, 3, 5)
plt.imshow(edges_sobel, cmap='gray')
plt.title('Sobel Edge Detection')
plt.axis('off')

# Laplacian Edge Detection
plt.subplot(2, 3, 6)
plt.imshow(edges_laplacian, cmap='gray')
plt.title('Laplacian Edge Detection')
plt.axis('off')

plt.tight_layout()
plt.show()

【後話】

在這篇文章中,我們講述了線稿的生成方式與不同用途,那在下篇,我們將透過 Canny Algorithm 展示各位,在不同的後製效果下,又會如何影響線稿的生成。

那我們就下期再會啦~

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.