160 lines
4.4 KiB
Python
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"
|