PictureEdit/transform_utils.py
2025-09-04 12:58:13 +08:00

117 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
作者:太一
微信taiyi1224
邮箱shuobo1224@qq.com
"""
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