การลบเส้นแนวนอน (Horizontal Lines) ออกจากภาพ เช่น ใบเสร็จ เอกสารสแกน หรือตาราง สามารถทำได้ด้วย Morphological Operations ใน OpenCV โดยใช้ Kernel แนวนอน
อัลกอริธึมหลัก
- อ่านภาพและแปลงเป็น Grayscale
- Thresholding (Binary Inverse + Otsu) เพื่อแยกเส้นสีดำบนพื้นขาว
- สร้าง Horizontal Kernel (กว้าง × สูง = 25 × 1)
- Morphological Opening: กรองเฉพาะโครงสร้างแนวนอน
- หา Contours ของเส้นที่ตรวจพบ
- วาดทับเส้นด้วยสีขาว (ลบออก)
- Morphological Closing ด้วย Vertical Kernel เพื่อซ่อมแซมข้อความที่หาย
ตัวอย่างโค้ดสมบูรณ์
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = [15, 10]
plt.rcParams["figure.autolayout"] = True
# 1. อ่านภาพ
image = cv2.imread('document_with_lines.jpg')
if image is None:
# สร้างภาพทดสอบหากไม่มีไฟล์
image = np.ones((600, 800, 3), dtype=np.uint8) * 255
# วาดเส้นแนวนอนปลอม
for y in range(50, 550, 60):
cv2.line(image, (50, y), (750, y), (0, 0, 0), 2)
# เพิ่มข้อความ
cv2.putText(image, "Sample Text Line 1", (60, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,0,0), 2)
cv2.putText(image, "Sample Text Line 2", (60, 140), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,0,0), 2)
cv2.putText(image, "Sample Text Line 3", (60, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,0,0), 2)
original = image.copy()
# 2. แปลง Grayscale และ Threshold
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# 3. Horizontal Kernel และ Morphological Opening
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1))
detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
# 4. หา Contours เส้นแนวนอน
contours, _ = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 5. ลบเส้นโดยวาดทับสีขาว (บนภาพต้นฉบับ)
for cnt in contours:
cv2.drawContours(image, [cnt], -1, (255, 255, 255), 3) # ความหนา 3 พิกเซล
# 6. ซ่อมแซมข้อความที่อาจหาย (Vertical Closing)
repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 6))
# Invert -> Close -> Invert กลับ
result = 255 - cv2.morphologyEx(255 - image, cv2.MORPH_CLOSE, repair_kernel, iterations=1)
# แสดงผล
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
titles = ['Original', 'Threshold (Inverted)', 'Detected Horizontal Lines', 'Result (Lines Removed)']
images = [original, thresh, detected_lines, result]
cmaps = [None, 'gray', 'gray', None]
for ax, img, title, cmap in zip(axes.flat, images, titles, cmaps):
if cmap:
ax.imshow(img, cmap=cmap)
else:
ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
ax.set_title(title, fontsize=12)
ax.axis('off')
plt.show()
ผลลัพธ์
ภาพต้นฉบับมีเส้นแนวนอนชัดเจน → หลังประมวลผล เส้นแนวนอนหายไป ข้อความยังคงสมบูรณ์
พารามิเตอร์สำคัญที่ต้องปรับ
- Horizontal Kernel Size:
(width, 1)- Width ควรกว้างกว่าความกว้างตัวอักษร ประมาณ 25-50 - Iterations ใน Opening: 1-2 รอบ เพื่อกรอง Noise
- Vertical Repair Kernel:
(1, height)- Height ประมาณความสูงตัวอักษร (4-8) - Thickness ใน drawContours: ควรหนาเล็กน้อยกว่าเส้นจริง (2-4)
กรณีพิเศษ: เส้นแนวตั้ง (Vertical Lines)
# เปลี่ยน Kernel เป็นแนวตั้ง vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 40)) detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) # ... ขั้นตอนเดียวกัน