111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
import math
|
||
|
||
import cv2
|
||
import numpy as np
|
||
|
||
class ResizeHandle:
|
||
"""图片缩放控制点"""
|
||
|
||
def __init__(self, position):
|
||
# 位置: 'tl', 'tr', 'bl', 'br' 分别代表四个顶点
|
||
self.position = position
|
||
self.active = False
|
||
self.x = 0
|
||
self.y = 0
|
||
self.radius = 5 # 控制点半径,从8减小到5
|
||
|
||
def hit_test(self, x, y):
|
||
"""检查点是否在控制范围内"""
|
||
dx = x - self.x
|
||
dy = y - self.y
|
||
return math.sqrt(dx * dx + dy * dy) <= self.radius
|
||
|
||
class TransformHelper:
|
||
"""图片变形辅助工具"""
|
||
|
||
@staticmethod
|
||
def calculate_handles(fg, canvas):
|
||
"""计算四个顶点的控制点位置"""
|
||
handles = {
|
||
'tl': ResizeHandle('tl'),
|
||
'tr': ResizeHandle('tr'),
|
||
'bl': ResizeHandle('bl'),
|
||
'br': ResizeHandle('br')
|
||
}
|
||
|
||
# 转换顶点坐标到画布坐标
|
||
for i, pos in enumerate(['tl', 'tr', 'bl', 'br']):
|
||
x, y = fg.vertices[i]
|
||
canvas_x, canvas_y = canvas.template_to_canvas(x, y)
|
||
handles[pos].x = canvas_x
|
||
handles[pos].y = canvas_y
|
||
|
||
return handles
|
||
|
||
@staticmethod
|
||
def update_vertices(fg, handle_pos, dx, dy, canvas):
|
||
"""根据拖动的控制点更新顶点坐标和图片尺寸"""
|
||
t_dx, t_dy = canvas.canvas_to_template(dx, dy)
|
||
idx_map = {'tl': 0, 'tr': 1, 'bl': 2, 'br': 3}
|
||
idx = idx_map[handle_pos]
|
||
|
||
# 更新对应顶点
|
||
x, y = fg.vertices[idx]
|
||
new_x, new_y = x + t_dx, y + t_dy
|
||
|
||
# 获取其他顶点
|
||
tl = fg.vertices[0] if idx != 0 else (new_x, new_y)
|
||
tr = fg.vertices[1] if idx != 1 else (new_x, new_y)
|
||
bl = fg.vertices[2] if idx != 2 else (new_x, new_y)
|
||
br = fg.vertices[3] if idx != 3 else (new_x, new_y)
|
||
|
||
# 计算宽度和高度
|
||
width = max(abs(tr[0] - tl[0]), abs(br[0] - bl[0]))
|
||
height = max(abs(bl[1] - tl[1]), abs(br[1] - tr[1]))
|
||
|
||
# 确保最小尺寸
|
||
if width < 10 or height < 10:
|
||
# 如果太小,则不更新
|
||
return fg
|
||
|
||
fg.vertices[idx] = (new_x, new_y)
|
||
|
||
return fg
|
||
|
||
@staticmethod
|
||
def get_perspective_matrix(src_vertices, dst_size):
|
||
"""计算透视变换矩阵"""
|
||
# 源坐标:图片四个角
|
||
src = np.float32([
|
||
[0, 0],
|
||
[dst_size[0], 0],
|
||
[0, dst_size[1]],
|
||
[dst_size[0], dst_size[1]]
|
||
])
|
||
|
||
# 目标坐标:变形后的四个角
|
||
dst = np.float32(src_vertices)
|
||
|
||
# 计算透视变换矩阵
|
||
return cv2.getPerspectiveTransform(src, dst)
|
||
@staticmethod
|
||
def update_image_size(fg, handle_pos, dx, dy, canvas):
|
||
"""根据拖动的控制点更新图片尺寸"""
|
||
t_dx, t_dy = canvas.canvas_to_template(dx, dy)
|
||
|
||
if handle_pos in ['nw', 'sw', 'w']:
|
||
fg.x += t_dx
|
||
fg.w -= t_dx
|
||
if handle_pos in ['ne', 'se', 'e']:
|
||
fg.w += t_dx
|
||
if handle_pos in ['nw', 'ne', 'n']:
|
||
fg.y += t_dy
|
||
fg.h -= t_dy
|
||
if handle_pos in ['sw', 'se', 's']:
|
||
fg.h += t_dy
|
||
|
||
# 确保尺寸为正值
|
||
fg.w = max(10, fg.w)
|
||
fg.h = max(10, fg.h)
|
||
|
||
return fg |