File size: 5,410 Bytes
a1916d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import numpy as np
import cv2

# --- 1. Convolution 2D (พื้นฐานของ Blur และ Sobel) ---
def convolution2d(image, kernel):
    """
    ทำ Convolution ระหว่างภาพกับ Kernel
    """
    # ดึงขนาดภาพและ Kernel
    image_h, image_w = image.shape
    kernel_h, kernel_w = kernel.shape
    
    # คำนวณ Padding (เพื่อให้ภาพผลลัพธ์ขนาดเท่าเดิม)
    pad_h = kernel_h // 2
    pad_w = kernel_w // 2
    
    # สร้างภาพที่มี Padding (ใช้ขอบเป็น 0)
    padded_image = np.pad(image, ((pad_h, pad_h), (pad_w, pad_w)), mode='constant')
    output = np.zeros_like(image)
    
    # วนลูป (Vectorized way เพื่อความเร็วที่ดีกว่า Loop ปกติ)
    # หมายเหตุ: การเขียน Loop ซ้อนกัน 2 ชั้นใน Python จะช้ามาก 
    # ตรงนี้จึงขอใช้ Numpy ช่วยในการคูณ Matrix เพื่อประสิทธิภาพ
    for y in range(image_h):
        for x in range(image_w):
            # ตัดส่วนของภาพที่ตรงกับ Kernel
            roi = padded_image[y:y+kernel_h, x:x+kernel_w]
            # คูณกันแล้วหาผลรวม (Element-wise multiplication & Sum)
            k = (roi * kernel).sum()
            output[y, x] = k
            
    return output

def gaussian_kernel(size=5, sigma=1.0):
    """ สร้าง Gaussian Kernel สำหรับทำ Smoothing """
    ax = np.linspace(-(size - 1) / 2., (size - 1) / 2., size)
    xx, yy = np.meshgrid(ax, ax)
    kernel = np.exp(-0.5 * (np.square(xx) + np.square(yy)) / np.square(sigma))
    return kernel / np.sum(kernel)

# --- 2. Sobel Edge Detection (เขียนเอง) ---
def sobel_edge_detection(image):
    # Kernel ของ Sobel แกน X และ Y
    Kx = np.array([[-1, 0, 1], 
                   [-2, 0, 2], 
                   [-1, 0, 1]], dtype=np.float32)
    
    Ky = np.array([[-1, -2, -1], 
                   [0, 0, 0], 
                   [1, 2, 1]], dtype=np.float32)
    
    # ทำ Convolution
    Ix = convolution2d(image, Kx)
    Iy = convolution2d(image, Ky)
    
    # คำนวณความแรงของขอบ (Gradient Magnitude)
    G = np.sqrt(Ix**2 + Iy**2)
    
    # Normalize ให้ค่าอยู่ช่วง 0-255
    G = (G / G.max()) * 255
    return G.astype(np.uint8)

# --- 3. Threshold (เขียนเอง) ---
def manual_threshold(image, thresh_value=100):
    """ เปลี่ยนภาพเป็น Binary (ขาว-ดำ) ตามค่า Threshold """
    binary_image = np.zeros_like(image)
    # ถ้า pixel ไหนค่ามากกว่า thresh_value ให้เป็น 255 (ขาว) นอกนั้น 0 (ดำ)
    binary_image[image > thresh_value] = 255
    return binary_image

# --- 4. Morphology - Dilation (เขียนเอง) ---
def manual_dilation(image, kernel_size=3):
    """ ขยายเส้นขอบให้หนาขึ้น (เชื่อมเส้นที่ขาด) """
    h, w = image.shape
    pad = kernel_size // 2
    padded_image = np.pad(image, ((pad, pad), (pad, pad)), mode='constant')
    output = np.zeros_like(image)
    
    # หลักการ Dilation: เลือกค่าที่ "มากที่สุด" ในหน้าต่าง Kernel
    for y in range(h):
        for x in range(w):
            roi = padded_image[y:y+kernel_size, x:x+kernel_size]
            output[y, x] = np.max(roi)
            
    return output

# --- 5. จัดเรียงจุดมุม (Perspective Transform Helper) ---
def order_points(pts):
    # (โค้ดเดิมที่เขียนเองถูกต้องแล้ว)
    rect = np.zeros((4, 2), dtype="float32")
    
    # บนซ้าย (ผลบวกน้อยสุด) / ล่างขวา (ผลบวกมากสุด)
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    
    # บนขวา (ผลต่างน้อยสุด) / ล่างซ้าย (ผลต่างมากสุด)
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    
    return rect

def four_point_transform(image, pts):
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    
    # คำนวณความกว้าง
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))
    
    # คำนวณความสูง
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))
    
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")
        
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    return warped