import sys
import numpy as np
import cv2
import os
def detect_largest_rectangle(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
kernel = np.ones((3,3), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
min_area = image.shape[0] * image.shape[1] * 0.3
valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area]
if not valid_contours:
return None
largest_contour = max(valid_contours, key=cv2.contourArea)
epsilon = 0.02 * cv2.arcLength(largest_contour, True)
approx = cv2.approxPolyDP(largest_contour, epsilon, True)
print(f"검출된 꼭지점 수: {len(approx)}")
if len(approx) == 4:
points = approx.reshape(4, 2).astype(np.float32)
rect = np.zeros((4, 2), dtype=np.float32)
s = points.sum(axis=1)
rect[0] = points[np.argmin(s)]
rect[2] = points[np.argmax(s)]
remaining_points = points[~np.isin(range(4), [np.argmin(s), np.argmax(s)])]
rect[1] = remaining_points[np.argmin(remaining_points[:, 0])]
rect[3] = remaining_points[np.argmax(remaining_points[:, 0])]
return rect
return None
def save_debug_image(image, name, output_dir, base_name):
debug_path = os.path.join(output_dir, f'{base_name}_{name}.jpg')
cv2.imwrite(debug_path, image)
print(f'Debug image saved as: {debug_path}')
def drawROI(img, corners):
cpy = img.copy()
c1 = (192, 192, 255)
c2 = (128, 128, 255)
for pt in corners:
cv2.circle(cpy, tuple(pt.astype(int)), 25, c1, -1, cv2.LINE_AA)
cv2.line(cpy, tuple(corners[0].astype(int)), tuple(corners[1].astype(int)), c2, 2, cv2.LINE_AA)
cv2.line(cpy, tuple(corners[1].astype(int)), tuple(corners[2].astype(int)), c2, 2, cv2.LINE_AA)
cv2.line(cpy, tuple(corners[2].astype(int)), tuple(corners[3].astype(int)), c2, 2, cv2.LINE_AA)
cv2.line(cpy, tuple(corners[3].astype(int)), tuple(corners[0].astype(int)), c2, 2, cv2.LINE_AA)
disp = cv2.addWeighted(img, 0.3, cpy, 0.7, 0)
return disp
if len(sys.argv) != 2:
print('Usage: python3 drawRectangle.py <image_path>')
sys.exit()
image_path = sys.argv[1]
src = cv2.imread(image_path)
if src is None:
print(f'Image open failed! Check if the file exists: {image_path}')
sys.exit()
output_dir = '/home/pi/'
base_name = os.path.splitext(os.path.basename(image_path))[0]
if not os.path.exists(output_dir):
os.makedirs(output_dir)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
kernel = np.ones((3,3), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
save_debug_image(gray, 'gray', output_dir, base_name)
save_debug_image(thresh, 'thresh', output_dir, base_name)
h, w = src.shape[:2]
dw = 500
dh = round(dw * 297 / 210)
srcQuad = detect_largest_rectangle(src)
if srcQuad is None:
print('Rectangle detection failed!')
sys.exit()
print("\n꼭지점 좌표:")
print(f"좌상단: ({int(srcQuad[0][0])}, {int(srcQuad[0][1])})")
print(f"좌하단: ({int(srcQuad[1][0])}, {int(srcQuad[1][1])})")
print(f"우하단: ({int(srcQuad[2][0])}, {int(srcQuad[2][1])})")
print(f"우상단: ({int(srcQuad[3][0])}, {int(srcQuad[3][1])})")
dstQuad = np.array([[0, 0], [0, dh-1], [dw-1, dh-1], [dw-1, 0]], np.float32)
disp = drawROI(src, srcQuad)
output_dir = '/home/pi'
if not os.path.exists(output_dir):
os.makedirs(output_dir)
detected_path = os.path.join(output_dir, f'{base_name}_detected.jpg')
transformed_path = os.path.join(output_dir, f'{base_name}_transformed.jpg')
cv2.imwrite(detected_path, disp)
pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(src, pers, (dw, dh), flags=cv2.INTER_CUBIC)
cv2.imwrite(transformed_path, dst)
print(f'Detected rectangle saved as: {detected_path}')
print(f'Transformed image saved as: {transformed_path}')
import cv2
import numpy as np
import os
def detect_paper_region(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
kernel = np.ones((5,5), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
contours, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
min_area = image.shape[0] * image.shape[1] * 0.05
max_area = image.shape[0] * image.shape[1] * 0.9
valid_contours = [cnt for cnt in contours if min_area < cv2.contourArea(cnt) < max_area]
if not valid_contours:
return None
largest_contour = max(valid_contours, key=cv2.contourArea)
epsilon = 0.02 * cv2.arcLength(largest_contour, True)
approx = cv2.approxPolyDP(largest_contour, epsilon, True)
if len(approx) != 4:
return None
return approx.reshape(4, 2)
def crop_to_paper_region(image, corners):
rect = np.zeros((4, 2), dtype=np.float32)
s = corners.sum(axis=1)
rect[0] = corners[np.argmin(s)]
rect[2] = corners[np.argmax(s)]
diff = np.diff(corners, axis=1)
rect[1] = corners[np.argmin(diff)]
rect[3] = corners[np.argmax(diff)]
width = max(np.linalg.norm(rect[2] - rect[3]), np.linalg.norm(rect[1] - rect[0]))
height = max(np.linalg.norm(rect[1] - rect[2]), np.linalg.norm(rect[0] - rect[3]))
dst = np.array([
[0, 0],
[width - 1, 0],
[width - 1, height - 1],
[0, height - 1]], dtype="float32")
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (int(width), int(height)))
return warped
def save_debug_image(image, name, output_dir, base_name):
debug_path = os.path.join(output_dir, f'{base_name}_{name}.jpg')
cv2.imwrite(debug_path, image)
print(f'Debug image saved as: {debug_path}')
def process_image(image_path, output_dir):
if not os.path.exists(image_path):
print(f"Error: {image_path} does not exist.")
return
image = cv2.imread(image_path)
if image is None:
print(f"Error: Cannot read {image_path}. Check the path.")
return
base_name = os.path.splitext(os.path.basename(image_path))[0]
paper_corners = detect_paper_region(image)
if paper_corners is None:
print('Paper detection failed!')
return
print("\nDetected Paper Corners:")
for i, corner in enumerate(paper_corners):
print(f"Corner {i+1}: ({int(corner[0])}, {int(corner[1])})")
cropped_image = crop_to_paper_region(image, paper_corners)
save_debug_image(cropped_image, 'cropped', output_dir, base_name)
path = "/home/pi/templates/upload/"
for file in os.listdir(path):
print(f"\nProcessing file: {file}")
file_path = os.path.join(path, file)
output_dir = '/home/pi/templates/upload'
process_image(file_path, output_dir)