Spaces:
Runtime error
Runtime error
code
Browse files- Segmentation.py +58 -0
- perpestive_transform.py +188 -0
Segmentation.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ultralytics import YOLO
|
| 2 |
+
import cv2
|
| 3 |
+
import os
|
| 4 |
+
import shutil
|
| 5 |
+
import numpy as np
|
| 6 |
+
def black_mask(results):
|
| 7 |
+
# Đường dẫn đến thư mục "runs"
|
| 8 |
+
runs_folder = "mask"
|
| 9 |
+
# Kiểm tra xem thư mục "mask" đã tồn tại chưa
|
| 10 |
+
if not os.path.exists(runs_folder):
|
| 11 |
+
# Nếu chưa tồn tại, tạo thư mục "mask"
|
| 12 |
+
os.makedirs(runs_folder)
|
| 13 |
+
for mask_index in range(len(results[0].masks)):
|
| 14 |
+
# Lấy mặt nạ
|
| 15 |
+
mask_raw = results[0].masks[mask_index].cpu().data.numpy().transpose(1, 2, 0)
|
| 16 |
+
# Chuyển đổi mặt nạ thành 3 kênh màu
|
| 17 |
+
mask_3channel = cv2.merge((mask_raw, mask_raw, mask_raw))
|
| 18 |
+
# Lấy kích thước của ảnh gốc (chiều cao, chiều rộng, số kênh)
|
| 19 |
+
h2, w2, c2 = results[0].orig_img.shape
|
| 20 |
+
# Thay đổi kích thước mặt nạ thành cùng kích thước với ảnh gốc
|
| 21 |
+
mask = cv2.resize(mask_3channel, (w2, h2))
|
| 22 |
+
# Chuyển đổi ảnh mặt nạ thành không gian màu HSV
|
| 23 |
+
hsv = cv2.cvtColor(mask, cv2.COLOR_BGR2HSV)
|
| 24 |
+
# Xác định phạm vi độ sáng trong không gian màu HSV
|
| 25 |
+
lower_black = np.array([0, 0, 0])
|
| 26 |
+
upper_black = np.array([0, 0, 1])
|
| 27 |
+
# Tạo mặt nạ dựa trên phạm vi độ sáng
|
| 28 |
+
mask = cv2.inRange(mask, lower_black, upper_black)
|
| 29 |
+
# Đảo ngược mặt nạ để lấy mọi thứ trừ màu đen
|
| 30 |
+
mask = cv2.bitwise_not(mask)
|
| 31 |
+
# Áp dụng mặt nạ vào ảnh gốc
|
| 32 |
+
masked = cv2.bitwise_and(results[0].orig_img, results[0].orig_img, mask=mask)
|
| 33 |
+
# Chuyển mọi pixel màu đen thành màu trắng
|
| 34 |
+
black_color = [0, 0, 0]
|
| 35 |
+
white_color = [255, 255, 255]
|
| 36 |
+
result_image = np.where(np.all(masked == black_color, axis=-1, keepdims=True), masked, white_color)
|
| 37 |
+
name = "mask/"+str(mask_index) + '.png'
|
| 38 |
+
# Show the masked part of the image
|
| 39 |
+
cv2.imwrite(name,result_image)
|
| 40 |
+
def segmentation_doc(image):
|
| 41 |
+
model = YOLO('Model/Seg65ep.pt')
|
| 42 |
+
runs_folder = "runs"
|
| 43 |
+
folder="mask"
|
| 44 |
+
# Xóa thư mục runs
|
| 45 |
+
if os.path.exists(runs_folder) and os.path.isdir(runs_folder):
|
| 46 |
+
# Xóa thư mục runs
|
| 47 |
+
shutil.rmtree(runs_folder)
|
| 48 |
+
if os.path.exists(folder) and os.path.isdir(folder):
|
| 49 |
+
# Xóa thư mục runs
|
| 50 |
+
shutil.rmtree(folder)
|
| 51 |
+
color = [255, 255, 255] # Màu trắng
|
| 52 |
+
padding_size = 50
|
| 53 |
+
image = cv2.copyMakeBorder(image, padding_size, padding_size, padding_size, padding_size, cv2.BORDER_CONSTANT, value=color)
|
| 54 |
+
results = model(image,save=True,retina_masks = True, conf=0.7)
|
| 55 |
+
black_mask(results)
|
| 56 |
+
return image
|
| 57 |
+
# image=cv2.imread("test1.jpg")
|
| 58 |
+
# segmentation_doc(image)
|
perpestive_transform.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cv2
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
from deskew import determine_skew
|
| 5 |
+
import math
|
| 6 |
+
from typing import Tuple, Union
|
| 7 |
+
def rotate(image: np.ndarray, angle: float, background: Union[int, Tuple[int, int, int]]) -> np.ndarray:
|
| 8 |
+
old_width, old_height = image.shape[:2]
|
| 9 |
+
angle_radian = math.radians(angle)
|
| 10 |
+
width = abs(np.sin(angle_radian) * old_height) + abs(np.cos(angle_radian) * old_width)
|
| 11 |
+
height = abs(np.sin(angle_radian) * old_width) + abs(np.cos(angle_radian) * old_height)
|
| 12 |
+
|
| 13 |
+
image_center = tuple(np.array(image.shape[1::-1]) / 2)
|
| 14 |
+
rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
|
| 15 |
+
rot_mat[1, 2] += (width - old_width) / 2
|
| 16 |
+
rot_mat[0, 2] += (height - old_height) / 2
|
| 17 |
+
|
| 18 |
+
return cv2.warpAffine(image, rot_mat, (int(round(height)), int(round(width))), borderValue=background)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def check(my_list):
|
| 22 |
+
unique_elements = []
|
| 23 |
+
|
| 24 |
+
# Sử dụng vòng lặp để kiểm tra từng phần tử trong danh sách
|
| 25 |
+
for item in my_list:
|
| 26 |
+
# 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 đó
|
| 27 |
+
if item not in unique_elements:
|
| 28 |
+
unique_elements.append(item)
|
| 29 |
+
return len(unique_elements)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def order_points(pts):
|
| 33 |
+
rect = np.zeros((4, 2), dtype="float32")
|
| 34 |
+
pts = np.array(pts)
|
| 35 |
+
s = pts.sum(axis=1)
|
| 36 |
+
rect[0] = pts[np.argmin(s)]
|
| 37 |
+
rect[2] = pts[np.argmax(s)]
|
| 38 |
+
|
| 39 |
+
diff = np.diff(pts, axis=1)
|
| 40 |
+
rect[1] = pts[np.argmin(diff)]
|
| 41 |
+
rect[3] = pts[np.argmax(diff)]
|
| 42 |
+
return rect.astype("int").tolist()
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def find_dest(pts):
|
| 46 |
+
(tl, tr, br, bl) = pts
|
| 47 |
+
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
|
| 48 |
+
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
|
| 49 |
+
maxWidth = max(int(widthA), int(widthB))
|
| 50 |
+
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
|
| 51 |
+
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
|
| 52 |
+
maxHeight = max(int(heightA), int(heightB))
|
| 53 |
+
destination_corners = [[0, 0], [maxWidth, 0], [maxWidth, maxHeight], [0, maxHeight]]
|
| 54 |
+
return order_points(destination_corners)
|
| 55 |
+
def extract(ori_img, img, image_size=384, BUFFER=100):
|
| 56 |
+
img=img.astype(np.uint8)
|
| 57 |
+
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
| 58 |
+
angle = determine_skew(gray_image)
|
| 59 |
+
img = rotate(img, angle, (0, 0, 0))
|
| 60 |
+
ori_img = rotate(ori_img, angle, (0, 0, 0))
|
| 61 |
+
#get size of image
|
| 62 |
+
size = img.shape
|
| 63 |
+
top_pad = 10 # Số pixel padding ở phía trên
|
| 64 |
+
bottom_pad = 10 # Số pixel padding ở phía dưới
|
| 65 |
+
left_pad = 10 # Số pixel padding ở phía trái
|
| 66 |
+
right_pad = 10 # Số pixel padding ở phía phải
|
| 67 |
+
|
| 68 |
+
# 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
|
| 69 |
+
height, width, channels = img.shape
|
| 70 |
+
new_height = height + top_pad + bottom_pad
|
| 71 |
+
new_width = width + left_pad + right_pad
|
| 72 |
+
|
| 73 |
+
# Tạo một hình ảnh mới với màu đen (0) là màu nền
|
| 74 |
+
padded_img = np.zeros((new_height, new_width, channels), dtype=np.uint8)
|
| 75 |
+
|
| 76 |
+
# Copy nội dung của hình ảnh gốc vào vị trí tương ứng trong hình ảnh mới
|
| 77 |
+
padded_img[top_pad:top_pad + height, left_pad:left_pad + width] = img
|
| 78 |
+
img = padded_img
|
| 79 |
+
|
| 80 |
+
height, width, channels = ori_img.shape
|
| 81 |
+
new_height = height + top_pad + bottom_pad
|
| 82 |
+
new_width = width + left_pad + right_pad
|
| 83 |
+
|
| 84 |
+
# Tạo một hình ảnh mới với màu đen (0) là màu nền
|
| 85 |
+
padded_ori_img = np.full((new_height, new_width, channels), 255, dtype=np.uint8)
|
| 86 |
+
|
| 87 |
+
# Copy nội dung của hình ảnh gốc vào vị trí tương ứng trong hình ảnh mới
|
| 88 |
+
padded_ori_img[top_pad:top_pad + height, left_pad:left_pad + width] = ori_img
|
| 89 |
+
ori_img = padded_ori_img
|
| 90 |
+
|
| 91 |
+
imH, imW, C = img.shape
|
| 92 |
+
IMAGE_SIZE = image_size
|
| 93 |
+
img_rs = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_NEAREST)
|
| 94 |
+
|
| 95 |
+
# imH, imW, C = img.shape
|
| 96 |
+
# IMAGE_SIZE=image_size
|
| 97 |
+
scale_x = imW / IMAGE_SIZE
|
| 98 |
+
scale_y = imH / IMAGE_SIZE
|
| 99 |
+
# img=cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_NEAREST)
|
| 100 |
+
|
| 101 |
+
canny = cv2.Canny(img_rs.astype(np.uint8), 225, 255)
|
| 102 |
+
canny = cv2.dilate(canny, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))
|
| 103 |
+
contours, _ = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
|
| 104 |
+
page = sorted(contours, key=cv2.contourArea, reverse=True)[0]
|
| 105 |
+
epsilon = (0.02* cv2.arcLength(page, True))
|
| 106 |
+
corners = cv2.approxPolyDP(page, epsilon, True)
|
| 107 |
+
corners = np.concatenate(corners).astype(np.float32)
|
| 108 |
+
corners[:, 0] *= scale_x
|
| 109 |
+
corners[:, 1] *= scale_y
|
| 110 |
+
|
| 111 |
+
# corners[:, 0] -= half
|
| 112 |
+
# corners[:, 1] -= half
|
| 113 |
+
for corner in corners:
|
| 114 |
+
x, y = corner.astype(int)
|
| 115 |
+
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
|
| 116 |
+
|
| 117 |
+
if len(corners) > 4:
|
| 118 |
+
left_pad, top_pad, right_pad, bottom_pad = 0, 0, 0, 0
|
| 119 |
+
rect = cv2.minAreaRect(corners.reshape((-1, 1, 2)))
|
| 120 |
+
box = cv2.boxPoints(rect)
|
| 121 |
+
box_corners = np.int32(box)
|
| 122 |
+
# box_corners = minimum_bounding_rectangle(corners)
|
| 123 |
+
|
| 124 |
+
box_x_min = np.min(box_corners[:, 0])
|
| 125 |
+
box_x_max = np.max(box_corners[:, 0])
|
| 126 |
+
box_y_min = np.min(box_corners[:, 1])
|
| 127 |
+
box_y_max = np.max(box_corners[:, 1])
|
| 128 |
+
|
| 129 |
+
# Find corner point which doesn't satify the image constraint
|
| 130 |
+
# and record the amount of shift required to make the box
|
| 131 |
+
# corner satisfy the constraint
|
| 132 |
+
if box_x_min <= 0:
|
| 133 |
+
left_pad = abs(box_x_min) + BUFFER
|
| 134 |
+
|
| 135 |
+
if box_x_max >= imW:
|
| 136 |
+
right_pad = (box_x_max - imW) + BUFFER
|
| 137 |
+
|
| 138 |
+
if box_y_min <= 0:
|
| 139 |
+
top_pad = abs(box_y_min) + BUFFER
|
| 140 |
+
|
| 141 |
+
if box_y_max >= imH:
|
| 142 |
+
bottom_pad = (box_y_max - imH) + BUFFER
|
| 143 |
+
box_corners[:, 0] += left_pad
|
| 144 |
+
box_corners[:, 1] += top_pad
|
| 145 |
+
corners = box_corners
|
| 146 |
+
|
| 147 |
+
if check(order_points(corners)) >= 4:
|
| 148 |
+
corners = order_points(corners)
|
| 149 |
+
else:
|
| 150 |
+
pass
|
| 151 |
+
|
| 152 |
+
# Define the amount to increase the rectangle size
|
| 153 |
+
# (tl, tr, br, bl) = corners
|
| 154 |
+
# widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
|
| 155 |
+
# widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
|
| 156 |
+
# maxWidth = max(int(widthA), int(widthB))
|
| 157 |
+
# heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
|
| 158 |
+
# heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
|
| 159 |
+
# maxHeight = max(int(heightA), int(heightB))
|
| 160 |
+
|
| 161 |
+
# # Increase the x-coordinate of the top-right and bottom-right points
|
| 162 |
+
# corners[1][0] += maxWidth/30
|
| 163 |
+
# corners[2][0] += maxWidth/30
|
| 164 |
+
|
| 165 |
+
# # Decrease the x-coordinate of the top-left and bottom-left points
|
| 166 |
+
# corners[0][0] -= maxWidth/30
|
| 167 |
+
# corners[3][0] -= maxWidth/30
|
| 168 |
+
# # Increase the y-coordinate of the bottom-right and bottom-left points
|
| 169 |
+
# corners[2][1] += maxHeight/30
|
| 170 |
+
# corners[3][1] += maxHeight/30
|
| 171 |
+
|
| 172 |
+
# # Decrease the y-coordinate of the top-left and top-right points
|
| 173 |
+
# corners[0][1] -= maxHeight/30
|
| 174 |
+
# corners[1][1] -= maxHeight/30
|
| 175 |
+
|
| 176 |
+
# print(corners)
|
| 177 |
+
|
| 178 |
+
destination_corners = find_dest(corners)
|
| 179 |
+
M = cv2.getPerspectiveTransform(np.float32(corners), np.float32(destination_corners))
|
| 180 |
+
final = cv2.warpPerspective(ori_img, M, (destination_corners[2][0], destination_corners[2][1]),
|
| 181 |
+
flags=cv2.INTER_LANCZOS4)
|
| 182 |
+
return final
|
| 183 |
+
# ori=cv2.imread("runs\segment\predict\image0.jpg")
|
| 184 |
+
# img=cv2.imread("mask/2.png")
|
| 185 |
+
# final=extract(ori,img)
|
| 186 |
+
# plt.imshow(final)
|
| 187 |
+
# plt.show()
|
| 188 |
+
# # print(img.shape)
|