Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

การลบเส้นแนวนอนในภาพด้วย OpenCV และ Matplotlib

การลบเส้นแนวนอน (Horizontal Lines) ออกจากภาพ เช่น ใบเสร็จ เอกสารสแกน หรือตาราง สามารถทำได้ด้วย Morphological Operations ใน OpenCV โดยใช้ Kernel แนวนอน

อัลกอริธึมหลัก

  1. อ่านภาพและแปลงเป็น Grayscale
  2. Thresholding (Binary Inverse + Otsu) เพื่อแยกเส้นสีดำบนพื้นขาว
  3. สร้าง Horizontal Kernel (กว้าง × สูง = 25 × 1)
  4. Morphological Opening: กรองเฉพาะโครงสร้างแนวนอน
  5. หา Contours ของเส้นที่ตรวจพบ
  6. วาดทับเส้นด้วยสีขาว (ลบออก)
  7. 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)
# ... ขั้นตอนเดียวกัน