Files
2025-11-10 11:11:52 +08:00

160 lines
4.4 KiB
Python

import cv2
import tkinter as tk
from tkinter import filedialog
import os
from utils_io import imread_unicode, imwrite_unicode
def select_image():
root = tk.Tk()
root.withdraw()
# 使用空格分隔多种后缀,兼容tkinter的filetypes
file_path = filedialog.askopenfilename(title='选择图片', filetypes=[('Image Files', '*.jpg *.png *.bmp *.jpeg')])
try:
root.update()
except Exception:
pass
finally:
try:
root.destroy()
except Exception:
pass
return file_path
def manual_roi(image_path):
# 读取原图(支持中文路径)
orig = imread_unicode(image_path)
if orig is None:
print('读取图片失败。')
return
h0, w0 = orig.shape[:2]
# 目标显示窗口较小尺寸(可改)
MAX_W, MAX_H = 1280, 960
# 计算等比缩放因子(不放大,只缩小)
scale = min(MAX_W / w0, MAX_H / h0, 1.0)
if scale < 1.0:
disp_w, disp_h = int(w0 * scale), int(h0 * scale)
disp = cv2.resize(orig, (disp_w, disp_h), interpolation=cv2.INTER_AREA)
else:
disp = orig.copy()
disp_h, disp_w = h0, w0
# 显示->原图 的坐标映射比例
sx = w0 / disp_w
sy = h0 / disp_h
base = disp.copy()
img = disp.copy()
roi = []
cropping = False
def draw_help(canvas):
# 轻量提示
cv2.putText(canvas, '拖动框选 | c 确认保存 | r 重选 | ESC 取消', (10, max(20, canvas.shape[0] - 10)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 1, cv2.LINE_AA)
def mouse_crop(event, x, y, flags, param):
nonlocal roi, cropping, img
if event == cv2.EVENT_LBUTTONDOWN:
roi = [(x, y)]
cropping = True
elif event == cv2.EVENT_MOUSEMOVE and cropping:
img = base.copy()
cv2.rectangle(img, roi[0], (x, y), (0, 255, 0), 2)
draw_help(img)
elif event == cv2.EVENT_LBUTTONUP:
roi.append((x, y))
cropping = False
img = base.copy()
cv2.rectangle(img, roi[0], roi[1], (0, 255, 0), 2)
draw_help(img)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.resizeWindow('image', disp_w, disp_h)
cv2.setMouseCallback('image', mouse_crop)
# 初始提示
draw_help(img)
while True:
cv2.imshow('image', img)
key = cv2.waitKey(10) & 0xFF
if key == ord('r'):
img = base.copy()
draw_help(img)
roi = []
elif key == ord('c'):
break
elif key == 27: # ESC
roi = []
break
cv2.destroyAllWindows()
if len(roi) == 2:
# 规范化显示坐标
x1, y1 = roi[0]
x2, y2 = roi[1]
x1, x2 = sorted((x1, x2))
y1, y2 = sorted((y1, y2))
# 将显示坐标映射回原图坐标
X1 = max(0, min(w0, int(round(x1 * sx))))
X2 = max(0, min(w0, int(round(x2 * sx))))
Y1 = max(0, min(h0, int(round(y1 * sy))))
Y2 = max(0, min(h0, int(round(y2 * sy))))
if X2 - X1 <= 0 or Y2 - Y1 <= 0:
print('选择区域过小或无效,未保存。')
return
X1,X2,Y1,Y2 = 346,402,139,227
# 裁剪ROI
roi_img = orig[Y1:Y2, X1:X2]
print(X1,X2,Y1,Y2)
# 确保输出目录存在(沿用你的固定路径)
out_dir = r"output"
os.makedirs(out_dir, exist_ok=True)
base_name = os.path.splitext(os.path.basename(image_path))[0]
# save_path = os.path.join(out_dir, f'{base_name}_roi.png')
save_path = os.path.join(out_dir, f'res_roi.png')
imwrite_unicode(save_path, roi_img)
print(f'ROI已保存到: {save_path}')
else:
print('未选择区域,未保存。')
return image_path
def interface_roi():
img_path = select_image()
input = r"output\res_roi.png"
image_high = 480
if img_path:
img = imread_unicode(img_path)
h, w = img.shape[:2]
image_high = h
image_path = manual_roi(img_path)
else:
print('未选择图片。')
image_path = input
# 调用line.py中的interface函数进行旋转校正
return input, image_high
if __name__ == '__main__':
img_path = select_image()
if img_path:
manual_roi(img_path)
else:
print('未选择图片。')
# 调用line.py中的interface函数进行旋转校正
input = r"output\res_roi.png"