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)