File size: 7,558 Bytes
7124da5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import cv2
import numpy as np
import matplotlib.pyplot as plt
from deskew import determine_skew
import math
from typing import Tuple, Union
def rotate(image: np.ndarray, angle: float, background: Union[int, Tuple[int, int, int]]) -> np.ndarray:
    old_width, old_height = image.shape[:2]
    angle_radian = math.radians(angle)
    width = abs(np.sin(angle_radian) * old_height) + abs(np.cos(angle_radian) * old_width)
    height = abs(np.sin(angle_radian) * old_width) + abs(np.cos(angle_radian) * old_height)

    image_center = tuple(np.array(image.shape[1::-1]) / 2)
    rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
    rot_mat[1, 2] += (width - old_width) / 2
    rot_mat[0, 2] += (height - old_height) / 2

    return cv2.warpAffine(image, rot_mat, (int(round(height)), int(round(width))), borderValue=background)


def check(my_list):
    unique_elements = []

    # Sử dụng vòng lặp để kiểm tra từng phần tử trong danh sách
    for item in my_list:
        # Nếu phần tử không xuất hiện trong danh sách các phần tử duy nhất, thêm nó vào danh sách đó
        if item not in unique_elements:
            unique_elements.append(item)
    return len(unique_elements)


def order_points(pts):
    rect = np.zeros((4, 2), dtype="float32")
    pts = np.array(pts)
    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.astype("int").tolist()


def find_dest(pts):
    (tl, tr, br, bl) = pts
    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))
    destination_corners = [[0, 0], [maxWidth, 0], [maxWidth, maxHeight], [0, maxHeight]]
    return order_points(destination_corners)
def extract(ori_img, img, image_size=384, BUFFER=100):
    img=img.astype(np.uint8)
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    angle = determine_skew(gray_image)
    img = rotate(img, angle, (0, 0, 0))
    ori_img = rotate(ori_img, angle, (0, 0, 0))
    #get size of image
    size = img.shape
    top_pad = 10     # Số pixel padding ở phía trên
    bottom_pad = 10   # Số pixel padding ở phía dưới
    left_pad = 10   # Số pixel padding ở phía trái
    right_pad = 10   # Số pixel padding ở phía phải

    # Tạo hình ảnh mới với kích thước lớn hơn, bằng cách thêm pixel màu đen (0) vào xung quanh
    height, width, channels = img.shape
    new_height = height + top_pad + bottom_pad
    new_width = width + left_pad + right_pad

    # Tạo một hình ảnh mới với màu đen (0) là màu nền
    padded_img = np.zeros((new_height, new_width, channels), dtype=np.uint8)

    # Copy nội dung của hình ảnh gốc vào vị trí tương ứng trong hình ảnh mới
    padded_img[top_pad:top_pad + height, left_pad:left_pad + width] = img
    img = padded_img

    height, width, channels = ori_img.shape
    new_height = height + top_pad + bottom_pad
    new_width = width + left_pad + right_pad

    # Tạo một hình ảnh mới với màu đen (0) là màu nền
    padded_ori_img = np.full((new_height, new_width, channels), 255, dtype=np.uint8)

    # Copy nội dung của hình ảnh gốc vào vị trí tương ứng trong hình ảnh mới
    padded_ori_img[top_pad:top_pad + height, left_pad:left_pad + width] = ori_img
    ori_img = padded_ori_img

    imH, imW, C = img.shape
    IMAGE_SIZE = image_size
    img_rs = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_NEAREST)

    # imH, imW, C = img.shape
    # IMAGE_SIZE=image_size
    scale_x = imW / IMAGE_SIZE
    scale_y = imH / IMAGE_SIZE
    # img=cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_NEAREST)

    canny = cv2.Canny(img_rs.astype(np.uint8), 225, 255)
    canny = cv2.dilate(canny, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))
    contours, _ = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    page = sorted(contours, key=cv2.contourArea, reverse=True)[0]
    epsilon = (0.02* cv2.arcLength(page, True))
    corners = cv2.approxPolyDP(page, epsilon, True)
    corners = np.concatenate(corners).astype(np.float32)
    corners[:, 0] *= scale_x
    corners[:, 1] *= scale_y

    # corners[:, 0] -= half
    # corners[:, 1] -= half
    for corner in corners:
        x, y = corner.astype(int)
        cv2.circle(img, (int(x), int(y)), 20, (0, 255, 0), -1)  # Vẽ một hình tròn màu xanh lên ảnh

    if len(corners) > 4:
        left_pad, top_pad, right_pad, bottom_pad = 0, 0, 0, 0
        rect = cv2.minAreaRect(corners.reshape((-1, 1, 2)))
        box = cv2.boxPoints(rect)
        box_corners = np.int32(box)
        #     box_corners = minimum_bounding_rectangle(corners)

        box_x_min = np.min(box_corners[:, 0])
        box_x_max = np.max(box_corners[:, 0])
        box_y_min = np.min(box_corners[:, 1])
        box_y_max = np.max(box_corners[:, 1])

        # Find corner point which doesn't satify the image constraint
        # and record the amount of shift required to make the box
        # corner satisfy the constraint
        if box_x_min <= 0:
            left_pad = abs(box_x_min) + BUFFER

        if box_x_max >= imW:
            right_pad = (box_x_max - imW) + BUFFER

        if box_y_min <= 0:
            top_pad = abs(box_y_min) + BUFFER

        if box_y_max >= imH:
            bottom_pad = (box_y_max - imH) + BUFFER
        box_corners[:, 0] += left_pad
        box_corners[:, 1] += top_pad
        corners = box_corners
    
    if check(order_points(corners)) >= 4:
        corners = order_points(corners)
    else:
        pass

# Define the amount to increase the rectangle size
    # (tl, tr, br, bl) = corners
    # 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))

    # # Increase the x-coordinate of the top-right and bottom-right points
    # corners[1][0] += maxWidth/30
    # corners[2][0] += maxWidth/30

    # # Decrease the x-coordinate of the top-left and bottom-left points
    # corners[0][0] -= maxWidth/30
    # corners[3][0] -= maxWidth/30
    # # Increase the y-coordinate of the bottom-right and bottom-left points
    # corners[2][1] += maxHeight/30
    # corners[3][1] += maxHeight/30

    # # Decrease the y-coordinate of the top-left and top-right points
    # corners[0][1] -= maxHeight/30
    # corners[1][1] -= maxHeight/30

    # print(corners)

    destination_corners = find_dest(corners)
    M = cv2.getPerspectiveTransform(np.float32(corners), np.float32(destination_corners))
    final = cv2.warpPerspective(ori_img, M, (destination_corners[2][0], destination_corners[2][1]),
                                flags=cv2.INTER_LANCZOS4)
    return final
# ori=cv2.imread("runs\segment\predict\image0.jpg")
# img=cv2.imread("mask/2.png")
# final=extract(ori,img)
# plt.imshow(final)
# plt.show()
# # print(img.shape)