mirror of
https://github.com/YaoFANGUK/video-subtitle-remover.git
synced 2026-05-01 22:17:34 +08:00
添加任务列表组件并优化视频加载逻辑 支持可视化显示字幕区域 整理所有模型, 分别为STTN智能擦除, STTN字幕检测, LAMA, ProPainter, OpenCV 提高处理性能 新增CPU运行模式并优化多语言支持 修复Propainter模式部分视频报错 本次提交新增了CPU运行模式,适用于无GPU加速的场景。同时,优化了多语言支持,新增了日语、韩语、越南语等语言配置文件,并更新了README文档以反映新的运行模式和多语言支持。此外,修复了部分代码逻辑,提升了系统的稳定性和兼容性。
566 lines
24 KiB
Python
566 lines
24 KiB
Python
import cv2
|
||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy
|
||
from PySide6.QtCore import Qt, Signal, QRect, QRectF, QTimer, QObject, QEvent
|
||
from PySide6 import QtCore, QtWidgets, QtGui
|
||
from qfluentwidgets import qconfig, CardWidget, HollowHandleStyle
|
||
|
||
from backend.config import config, tr
|
||
|
||
class VideoDisplayComponent(QWidget):
|
||
"""视频显示组件,包含视频预览和选择框功能"""
|
||
|
||
# 定义信号
|
||
selection_changed = Signal(QRect) # 选择框变化信号
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
self.parent = parent
|
||
|
||
# 初始化变量
|
||
self.is_drawing = False
|
||
self.selection_rect = QRect()
|
||
self.drag_start_pos = None
|
||
self.resize_edge = None
|
||
self.edge_size = 10 # 调整大小的边缘区域
|
||
self.enable_mouse_events = True # 控制是否启用鼠标事件
|
||
|
||
# 获取屏幕大小
|
||
screen = QtWidgets.QApplication.primaryScreen().size()
|
||
self.screen_width = screen.width()
|
||
self.screen_height = screen.height()
|
||
|
||
# 设置视频预览区域大小(根据屏幕宽度动态调整)
|
||
self.video_preview_width = 960
|
||
self.video_preview_height = self.video_preview_width * 9 // 16
|
||
if self.screen_width // 2 < 960:
|
||
self.video_preview_width = 640
|
||
self.video_preview_height = self.video_preview_width * 9 // 16
|
||
|
||
# 视频相关参数
|
||
self.frame_width = None
|
||
self.frame_height = None
|
||
self.scaled_width = None
|
||
self.scaled_height = None
|
||
self.border_left = 0
|
||
self.border_top = 0
|
||
|
||
# 保存选择框的相对位置和大小(相对于实际视频的比例)
|
||
self.selection_ratio = None
|
||
|
||
self.__initWidget()
|
||
|
||
def __initWidget(self):
|
||
"""初始化组件"""
|
||
main_layout = QVBoxLayout(self)
|
||
main_layout.setSpacing(0)
|
||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||
|
||
# 视频预览区域和进度条容器
|
||
self.video_container = CardWidget(self)
|
||
self.video_container.setObjectName('videoContainer')
|
||
video_layout = QVBoxLayout()
|
||
video_layout.setSpacing(0)
|
||
video_layout.setContentsMargins(2, 2, 2, 2)
|
||
video_layout.setAlignment(Qt.AlignCenter)
|
||
|
||
# 创建内部黑色背景容器
|
||
self.black_container = QWidget(self)
|
||
self.black_container.setObjectName('blackContainer')
|
||
self.black_container.setStyleSheet("""
|
||
#blackContainer {
|
||
background-color: black;
|
||
border-radius: 10px;
|
||
border: 0px solid transparent;
|
||
}
|
||
""")
|
||
black_layout = QVBoxLayout()
|
||
black_layout.setContentsMargins(0, 0, 0, 0)
|
||
black_layout.setSpacing(0)
|
||
black_layout.setAlignment(Qt.AlignCenter)
|
||
|
||
# 视频显示标签
|
||
self.video_display = QtWidgets.QLabel()
|
||
self.video_display.setStyleSheet("""
|
||
background-color: black;
|
||
border-top-left-radius: 10px;
|
||
border-top-right-radius: 10px;
|
||
border: 0px solid transparent;
|
||
""")
|
||
self.video_display.setMinimumSize(self.video_preview_width, self.video_preview_height)
|
||
|
||
self.video_display.setMouseTracking(True)
|
||
self.video_display.setScaledContents(True)
|
||
self.video_display.setAlignment(Qt.AlignCenter)
|
||
self.video_display.mousePressEvent = self.selection_mouse_press
|
||
self.video_display.mouseMoveEvent = self.selection_mouse_move
|
||
self.video_display.mouseReleaseEvent = self.selection_mouse_release
|
||
|
||
# 视频滑块
|
||
self.video_slider = QtWidgets.QSlider(Qt.Horizontal)
|
||
self.video_slider.setMinimum(1)
|
||
self.video_slider.setFixedHeight(22)
|
||
self.video_slider.setMaximum(100) # 默认最大值设为100,与进度百分比一致
|
||
self.video_slider.setValue(1)
|
||
self.video_slider.setStyle(HollowHandleStyle({
|
||
"handle.color": QtGui.QColor(255, 255, 255),
|
||
"handle.ring-width": 4,
|
||
"handle.hollow-radius": 6,
|
||
"handle.margin": 1
|
||
}))
|
||
|
||
# 视频预览区域
|
||
self.video_display.setObjectName('videoDisplay')
|
||
# black_layout.addWidget(self.video_display, 0, Qt.AlignCenter)
|
||
# 创建一个容器来保持比例
|
||
ratio_container = QWidget()
|
||
ratio_layout = QVBoxLayout(ratio_container)
|
||
ratio_layout.setContentsMargins(0, 0, 0, 0)
|
||
ratio_layout.addWidget(self.video_display)
|
||
|
||
# 设置固定的宽高比
|
||
ratio_container.setFixedHeight(ratio_container.width() * 9 // 16)
|
||
ratio_container.setMinimumWidth(self.video_preview_width)
|
||
|
||
# 添加到布局
|
||
black_layout.addWidget(ratio_container)
|
||
|
||
# 添加一个事件过滤器来处理大小变化
|
||
class RatioEventFilter(QObject):
|
||
def eventFilter(self, obj, event):
|
||
if event.type() == QEvent.Resize:
|
||
obj.setFixedHeight(obj.width() * 9 // 16)
|
||
return False
|
||
|
||
ratio_filter = RatioEventFilter(ratio_container)
|
||
ratio_container.installEventFilter(ratio_filter)
|
||
|
||
# 进度条和滑块容器
|
||
control_container = QWidget(self)
|
||
control_layout = QVBoxLayout()
|
||
control_layout.setContentsMargins(8, 8, 8, 8)
|
||
control_layout.addWidget(self.video_slider)
|
||
|
||
control_container.setLayout(control_layout)
|
||
control_container.setStyleSheet("""
|
||
background-color: black;
|
||
border-bottom-left-radius: 8px;
|
||
border-bottom-right-radius: 8px;
|
||
""")
|
||
black_layout.addWidget(control_container)
|
||
|
||
self.black_container.setLayout(black_layout)
|
||
video_layout.addWidget(self.black_container)
|
||
self.video_container.setLayout(video_layout)
|
||
main_layout.addWidget(self.video_container)
|
||
|
||
def update_video_display(self, frame, draw_selection=True):
|
||
"""更新视频显示"""
|
||
if frame is None:
|
||
return
|
||
|
||
# 调整视频帧大小以适应视频预览区域
|
||
frame = cv2.resize(frame, (self.video_preview_width, self.video_preview_height))
|
||
# 将 OpenCV 帧(BGR 格式)转换为 QImage 并显示在 QLabel 上
|
||
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||
h, w, ch = rgb_frame.shape
|
||
bytes_per_line = ch * w
|
||
image = QtGui.QImage(rgb_frame.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
|
||
pix = QtGui.QPixmap.fromImage(image)
|
||
|
||
# 创建带圆角的图像
|
||
rounded_pix = QtGui.QPixmap(pix.size())
|
||
rounded_pix.fill(Qt.transparent) # 填充透明背景
|
||
|
||
painter = QtGui.QPainter(rounded_pix)
|
||
painter.setRenderHint(QtGui.QPainter.Antialiasing) # 抗锯齿
|
||
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
|
||
|
||
# 创建圆角路径
|
||
path = QtGui.QPainterPath()
|
||
rect = QRectF(0, 0, pix.width(), pix.height())
|
||
|
||
# 手动创建只有左上和右上圆角的路径
|
||
radius = 8
|
||
path.moveTo(radius, 0)
|
||
path.lineTo(pix.width() - radius, 0)
|
||
path.arcTo(pix.width() - radius * 2, 0, radius * 2, radius * 2, 90, -90)
|
||
path.lineTo(pix.width(), pix.height())
|
||
path.lineTo(0, pix.height())
|
||
path.lineTo(0, radius)
|
||
path.arcTo(0, 0, radius * 2, radius * 2, 180, -90)
|
||
path.closeSubpath()
|
||
|
||
painter.setClipPath(path)
|
||
painter.drawPixmap(0, 0, pix)
|
||
painter.end()
|
||
|
||
# 保存当前的pixmap用于绘制选择框
|
||
self.current_pixmap = rounded_pix.copy()
|
||
|
||
self.video_display.setPixmap(rounded_pix)
|
||
|
||
# 如果有保存的选择框比例,根据新视频尺寸重新计算选择框
|
||
if draw_selection and self.selection_ratio is not None and self.scaled_width and self.scaled_height:
|
||
x_ratio, y_ratio, w_ratio, h_ratio = self.selection_ratio
|
||
|
||
# 计算新的选择框坐标和大小
|
||
x = int(x_ratio * self.scaled_width) + self.border_left
|
||
y = int(y_ratio * self.scaled_height) + self.border_top
|
||
w = int(w_ratio * self.scaled_width)
|
||
h = int(h_ratio * self.scaled_height)
|
||
|
||
# 创建新的选择框
|
||
self.selection_rect = QRect(x, y, w, h)
|
||
|
||
# 更新视频显示
|
||
self.update_preview_with_rect()
|
||
|
||
def update_preview_with_rect(self, rect=None):
|
||
"""更新带有选择框的预览"""
|
||
if not hasattr(self, 'current_pixmap') or self.current_pixmap is None:
|
||
return
|
||
|
||
# 如果提供了新的矩形,使用它
|
||
if rect is not None:
|
||
self.selection_rect = rect
|
||
|
||
# 创建一个副本用于绘制
|
||
pixmap_copy = self.current_pixmap.copy()
|
||
painter = QtGui.QPainter(pixmap_copy)
|
||
|
||
# 设置选择框样式
|
||
pen = QtGui.QPen(QtGui.QColor(0, 255, 0)) # 绿色
|
||
pen.setWidth(2)
|
||
painter.setPen(pen)
|
||
|
||
# 绘制选择框
|
||
painter.drawRect(self.selection_rect)
|
||
painter.end()
|
||
|
||
# 更新显示
|
||
self.video_display.setPixmap(pixmap_copy)
|
||
|
||
def selection_mouse_press(self, event):
|
||
"""鼠标按下事件处理"""
|
||
if not self.enable_mouse_events:
|
||
return
|
||
pos = event.pos()
|
||
|
||
# 检测双击或三击,重置选择框
|
||
if event.type() == QtCore.QEvent.MouseButtonDblClick:
|
||
self.selection_rect = QRect(pos, pos)
|
||
self.resize_edge = None
|
||
self.is_drawing = True
|
||
self.drag_start_pos = pos
|
||
return
|
||
|
||
# 检查是否在选择框边缘(用于调整大小)
|
||
if self.selection_rect.isValid():
|
||
# 右下角
|
||
if abs(pos.x() - self.selection_rect.right()) <= self.edge_size and abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size:
|
||
self.resize_edge = "bottomright"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 右上角
|
||
elif abs(pos.x() - self.selection_rect.right()) <= self.edge_size and abs(pos.y() - self.selection_rect.top()) <= self.edge_size:
|
||
self.resize_edge = "topright"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 左下角
|
||
elif abs(pos.x() - self.selection_rect.left()) <= self.edge_size and abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size:
|
||
self.resize_edge = "bottomleft"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 左边缘
|
||
elif abs(pos.x() - self.selection_rect.left()) <= self.edge_size and self.selection_rect.top() <= pos.y() <= self.selection_rect.bottom():
|
||
self.resize_edge = "left"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 右边缘
|
||
elif abs(pos.x() - self.selection_rect.right()) <= self.edge_size and self.selection_rect.top() <= pos.y() <= self.selection_rect.bottom():
|
||
self.resize_edge = "right"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 上边缘
|
||
elif abs(pos.y() - self.selection_rect.top()) <= self.edge_size and self.selection_rect.left() <= pos.x() <= self.selection_rect.right():
|
||
self.resize_edge = "top"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 下边缘
|
||
elif abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size and self.selection_rect.left() <= pos.x() <= self.selection_rect.right():
|
||
self.resize_edge = "bottom"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 左上角
|
||
elif abs(pos.x() - self.selection_rect.left()) <= self.edge_size and abs(pos.y() - self.selection_rect.top()) <= self.edge_size:
|
||
self.resize_edge = "topleft"
|
||
self.drag_start_pos = pos
|
||
return
|
||
# 在选择框内部(用于移动)
|
||
elif self.selection_rect.contains(pos):
|
||
self.resize_edge = "move"
|
||
self.drag_start_pos = pos
|
||
return
|
||
|
||
# 开始新的选择
|
||
self.is_drawing = True
|
||
self.selection_rect = QRect(pos, pos)
|
||
self.drag_start_pos = pos
|
||
self.resize_edge = None
|
||
|
||
def selection_mouse_move(self, event):
|
||
"""鼠标移动事件处理"""
|
||
if not self.enable_mouse_events:
|
||
return
|
||
pos = event.pos()
|
||
|
||
# 根据不同的操作模式处理鼠标移动
|
||
if self.is_drawing: # 绘制新选择框
|
||
self.selection_rect.setBottomRight(pos)
|
||
self.update_preview_with_rect()
|
||
elif self.resize_edge: # 调整选择框大小或位置
|
||
if self.resize_edge == "move":
|
||
# 移动整个选择框
|
||
dx = pos.x() - self.drag_start_pos.x()
|
||
dy = pos.y() - self.drag_start_pos.y()
|
||
|
||
# 保存原始选择框尺寸
|
||
original_width = self.selection_rect.width()
|
||
original_height = self.selection_rect.height()
|
||
|
||
# 计算新位置
|
||
new_rect = self.selection_rect.translated(dx, dy)
|
||
|
||
# 获取视频显示区域
|
||
display_rect = self.video_display.rect()
|
||
|
||
# 检查是否超出边界,如果超出则调整位置但保持尺寸
|
||
if new_rect.left() < 0:
|
||
new_rect.moveLeft(0)
|
||
if new_rect.top() < 0:
|
||
new_rect.moveTop(0)
|
||
if new_rect.right() > display_rect.width():
|
||
new_rect.moveRight(display_rect.width())
|
||
if new_rect.bottom() > display_rect.height():
|
||
new_rect.moveBottom(display_rect.height())
|
||
|
||
# 确保尺寸不变
|
||
if new_rect.width() != original_width or new_rect.height() != original_height:
|
||
# 如果尺寸变了,恢复原始尺寸
|
||
if new_rect.left() == 0:
|
||
new_rect.setWidth(original_width)
|
||
if new_rect.top() == 0:
|
||
new_rect.setHeight(original_height)
|
||
if new_rect.right() == display_rect.width():
|
||
new_rect.setLeft(new_rect.right() - original_width)
|
||
if new_rect.bottom() == display_rect.height():
|
||
new_rect.setTop(new_rect.bottom() - original_height)
|
||
|
||
self.selection_rect = new_rect
|
||
self.drag_start_pos = pos
|
||
else:
|
||
# 调整选择框大小
|
||
if "left" in self.resize_edge:
|
||
self.selection_rect.setLeft(pos.x())
|
||
if "right" in self.resize_edge:
|
||
self.selection_rect.setRight(pos.x())
|
||
if "top" in self.resize_edge:
|
||
self.selection_rect.setTop(pos.y())
|
||
if "bottom" in self.resize_edge:
|
||
self.selection_rect.setBottom(pos.y())
|
||
|
||
# 确保选择框在视频显示区域内
|
||
display_rect = self.video_display.rect()
|
||
if self.selection_rect.left() < 0:
|
||
self.selection_rect.setLeft(0)
|
||
if self.selection_rect.top() < 0:
|
||
self.selection_rect.setTop(0)
|
||
if self.selection_rect.right() > display_rect.width():
|
||
self.selection_rect.setRight(display_rect.width())
|
||
if self.selection_rect.bottom() > display_rect.height():
|
||
self.selection_rect.setBottom(display_rect.height())
|
||
|
||
self.update_preview_with_rect()
|
||
else:
|
||
# 更新鼠标指针形状
|
||
self.update_cursor_shape(pos)
|
||
|
||
def selection_mouse_release(self, event):
|
||
"""鼠标释放事件处理"""
|
||
if not self.enable_mouse_events:
|
||
return
|
||
# 结束绘制或调整
|
||
self.is_drawing = False
|
||
self.resize_edge = None
|
||
|
||
# 标准化选择框(确保宽度和高度为正)
|
||
self.selection_rect = self.selection_rect.normalized()
|
||
|
||
# 保存选择框的相对位置和大小
|
||
self.save_selection_ratio()
|
||
|
||
# 发送选择框变化信号
|
||
self.selection_changed.emit(self.selection_rect)
|
||
|
||
def update_cursor_shape(self, pos):
|
||
"""根据鼠标位置更新光标形状"""
|
||
if not self.selection_rect.isValid():
|
||
self.video_display.setCursor(Qt.ArrowCursor)
|
||
return
|
||
|
||
# 检查鼠标是否在选择框边缘
|
||
if (abs(pos.x() - self.selection_rect.left()) <= self.edge_size and
|
||
self.selection_rect.top() <= pos.y() <= self.selection_rect.bottom()):
|
||
self.video_display.setCursor(Qt.SizeHorCursor)
|
||
elif (abs(pos.x() - self.selection_rect.right()) <= self.edge_size and
|
||
self.selection_rect.top() <= pos.y() <= self.selection_rect.bottom()):
|
||
self.video_display.setCursor(Qt.SizeHorCursor)
|
||
elif (abs(pos.y() - self.selection_rect.top()) <= self.edge_size and
|
||
self.selection_rect.left() <= pos.x() <= self.selection_rect.right()):
|
||
self.video_display.setCursor(Qt.SizeVerCursor)
|
||
elif (abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size and
|
||
self.selection_rect.left() <= pos.x() <= self.selection_rect.right()):
|
||
self.video_display.setCursor(Qt.SizeVerCursor)
|
||
elif (abs(pos.x() - self.selection_rect.left()) <= self.edge_size and
|
||
abs(pos.y() - self.selection_rect.top()) <= self.edge_size):
|
||
self.video_display.setCursor(Qt.SizeFDiagCursor)
|
||
elif (abs(pos.x() - self.selection_rect.right()) <= self.edge_size and
|
||
abs(pos.y() - self.selection_rect.top()) <= self.edge_size):
|
||
self.video_display.setCursor(Qt.SizeBDiagCursor)
|
||
elif (abs(pos.x() - self.selection_rect.left()) <= self.edge_size and
|
||
abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size):
|
||
self.video_display.setCursor(Qt.SizeBDiagCursor)
|
||
elif (abs(pos.x() - self.selection_rect.right()) <= self.edge_size and
|
||
abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size):
|
||
self.video_display.setCursor(Qt.SizeFDiagCursor)
|
||
elif self.selection_rect.contains(pos):
|
||
self.video_display.setCursor(Qt.SizeAllCursor)
|
||
else:
|
||
self.video_display.setCursor(Qt.ArrowCursor)
|
||
|
||
def set_video_parameters(self, frame_width, frame_height, scaled_width=None, scaled_height=None, border_left=0, border_top=0):
|
||
"""设置视频参数"""
|
||
self.frame_width = frame_width
|
||
self.frame_height = frame_height
|
||
self.scaled_width = scaled_width
|
||
self.scaled_height = scaled_height
|
||
self.border_left = border_left
|
||
self.border_top = border_top
|
||
|
||
def get_selection_coordinates(self):
|
||
"""获取选择框坐标"""
|
||
return self.selection_rect
|
||
|
||
def set_selection_rect(self, rect):
|
||
"""设置选择框"""
|
||
self.selection_rect = rect
|
||
self.save_selection_ratio()
|
||
self.update_preview_with_rect()
|
||
|
||
def load_selection_ratio(self):
|
||
"""从配置中加载选择框的相对位置和大小"""
|
||
# 检查是否有有效的视频尺寸
|
||
if not self.scaled_width or not self.scaled_height:
|
||
return False
|
||
|
||
# 从配置中读取选择框的相对位置和大小
|
||
x_ratio = config.subtitleSelectionAreaX.value
|
||
y_ratio = config.subtitleSelectionAreaY.value
|
||
w_ratio = config.subtitleSelectionAreaW.value
|
||
h_ratio = config.subtitleSelectionAreaH.value
|
||
|
||
# 检查配置值是否有效
|
||
if x_ratio is None or y_ratio is None or w_ratio is None or h_ratio is None:
|
||
return False
|
||
|
||
# 检查配置值是否在有效范围内
|
||
if w_ratio <= 0.01 or h_ratio <= 0.005:
|
||
config.set(config.subtitleSelectionAreaX, config.subtitleSelectionAreaX.defaultValue)
|
||
config.set(config.subtitleSelectionAreaY, config.subtitleSelectionAreaY.defaultValue)
|
||
config.set(config.subtitleSelectionAreaW, config.subtitleSelectionAreaW.defaultValue)
|
||
config.set(config.subtitleSelectionAreaH, config.subtitleSelectionAreaH.defaultValue)
|
||
x_ratio = config.subtitleSelectionAreaX.value
|
||
y_ratio = config.subtitleSelectionAreaY.value
|
||
w_ratio = config.subtitleSelectionAreaW.value
|
||
h_ratio = config.subtitleSelectionAreaH.value
|
||
|
||
# 保存选择框比例
|
||
self.selection_ratio = (x_ratio, y_ratio, w_ratio, h_ratio)
|
||
|
||
# 计算实际像素坐标
|
||
x = int(x_ratio * self.scaled_width) + self.border_left
|
||
y = int(y_ratio * self.scaled_height) + self.border_top
|
||
w = int(w_ratio * self.scaled_width)
|
||
h = int(h_ratio * self.scaled_height)
|
||
|
||
# 创建选择框
|
||
self.selection_rect = QRect(x, y, w, h)
|
||
|
||
# 更新预览
|
||
self.update_preview_with_rect()
|
||
|
||
return True
|
||
|
||
def save_selection_ratio(self):
|
||
"""保存选择框的相对位置和大小(相对于实际视频的比例)"""
|
||
if not self.selection_rect.isValid() or not self.scaled_width or not self.scaled_height:
|
||
return
|
||
|
||
# 调整选择框坐标,考虑黑边偏移
|
||
x_adjusted = max(0, self.selection_rect.x() - self.border_left)
|
||
y_adjusted = max(0, self.selection_rect.y() - self.border_top)
|
||
|
||
# 如果选择框超出了实际视频区域,需要调整宽度和高度
|
||
w_adjusted = min(self.selection_rect.width(), self.scaled_width - x_adjusted)
|
||
h_adjusted = min(self.selection_rect.height(), self.scaled_height - y_adjusted)
|
||
|
||
# 转换为相对比例
|
||
x_ratio = x_adjusted / self.scaled_width
|
||
y_ratio = y_adjusted / self.scaled_height
|
||
w_ratio = w_adjusted / self.scaled_width
|
||
h_ratio = h_adjusted / self.scaled_height
|
||
|
||
self.selection_ratio = (x_ratio, y_ratio, w_ratio, h_ratio)
|
||
|
||
config.subtitleSelectionAreaY.value = y_ratio
|
||
config.subtitleSelectionAreaH.value = h_ratio
|
||
config.subtitleSelectionAreaX.value = x_ratio
|
||
config.subtitleSelectionAreaW.value = w_ratio
|
||
|
||
qconfig.save()
|
||
|
||
def get_original_coordinates(self):
|
||
"""获取选择框在原始视频中的坐标"""
|
||
if not self.selection_rect.isValid() or not self.scaled_width or not self.scaled_height:
|
||
return None
|
||
|
||
# 调整选择框坐标,考虑黑边偏移
|
||
x_adjusted = max(0, self.selection_rect.x() - self.border_left)
|
||
y_adjusted = max(0, self.selection_rect.y() - self.border_top)
|
||
|
||
# 如果选择框超出了实际视频区域,需要调整宽度和高度
|
||
w_adjusted = min(self.selection_rect.width(), self.scaled_width - x_adjusted)
|
||
h_adjusted = min(self.selection_rect.height(), self.scaled_height - y_adjusted)
|
||
|
||
# 转换为原始视频坐标
|
||
scale_x = self.frame_width / self.scaled_width
|
||
scale_y = self.frame_height / self.scaled_height
|
||
|
||
xmin = int(x_adjusted * scale_x)
|
||
xmax = int((x_adjusted + w_adjusted) * scale_x)
|
||
ymin = int(y_adjusted * scale_y)
|
||
ymax = int((y_adjusted + h_adjusted) * scale_y)
|
||
|
||
# 确保坐标在有效范围内
|
||
xmin = max(0, min(xmin, self.frame_width))
|
||
xmax = max(0, min(xmax, self.frame_width))
|
||
ymin = max(0, min(ymin, self.frame_height))
|
||
ymax = max(0, min(ymax, self.frame_height))
|
||
|
||
return (ymin, ymax, xmin, xmax)
|
||
|
||
def set_dragger_enabled(self, enabled):
|
||
"""设置拖动器是否可用"""
|
||
self.enable_mouse_events = enabled
|
||
self.video_display.setMouseTracking(enabled)
|
||
self.video_display.setCursor(Qt.ArrowCursor) |