Skip to content

Commit caa3316

Browse files
committed
同步VSR对于视频预览区域以及选区的改进
1 parent bf0fa69 commit caa3316

File tree

2 files changed

+165
-112
lines changed

2 files changed

+165
-112
lines changed

ui/component/video_display_component.py

Lines changed: 140 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import cv2
2-
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
3-
from PySide6.QtCore import Qt, Signal, QRect, QRectF
2+
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy
3+
from PySide6.QtCore import Qt, Signal, QRect, QRectF, QTimer, QObject, QEvent
44
from PySide6 import QtCore, QtWidgets, QtGui
55
from qfluentwidgets import qconfig, CardWidget, HollowHandleStyle
66

@@ -22,6 +22,7 @@ def __init__(self, parent=None):
2222
self.drag_start_pos = None
2323
self.resize_edge = None
2424
self.edge_size = 10 # 调整大小的边缘区域
25+
self.enable_mouse_events = True # 控制是否启用鼠标事件
2526

2627
# 获取屏幕大小
2728
screen = QtWidgets.QApplication.primaryScreen().size()
@@ -45,7 +46,7 @@ def __init__(self, parent=None):
4546

4647
# 保存选择框的相对位置和大小(相对于实际视频的比例)
4748
self.selection_ratio = None
48-
49+
4950
self.__initWidget()
5051

5152
def __initWidget(self):
@@ -68,7 +69,8 @@ def __initWidget(self):
6869
self.black_container.setStyleSheet("""
6970
#blackContainer {
7071
background-color: black;
71-
border-radius: 8px;
72+
border-radius: 10px;
73+
border: 0px solid transparent;
7274
}
7375
""")
7476
black_layout = QVBoxLayout()
@@ -80,11 +82,15 @@ def __initWidget(self):
8082
self.video_display = QtWidgets.QLabel()
8183
self.video_display.setStyleSheet("""
8284
background-color: black;
83-
border-top-left-radius: 8px;
84-
border-top-right-radius: 8px;
85+
border-top-left-radius: 10px;
86+
border-top-right-radius: 10px;
87+
border: 0px solid transparent;
8588
""")
86-
self.video_display.setFixedSize(self.video_preview_width, self.video_preview_height)
89+
self.video_display.setMinimumSize(self.video_preview_width, self.video_preview_height)
90+
8791
self.video_display.setMouseTracking(True)
92+
self.video_display.setScaledContents(True)
93+
self.video_display.setAlignment(Qt.AlignCenter)
8894
self.video_display.mousePressEvent = self.selection_mouse_press
8995
self.video_display.mouseMoveEvent = self.selection_mouse_move
9096
self.video_display.mouseReleaseEvent = self.selection_mouse_release
@@ -104,8 +110,30 @@ def __initWidget(self):
104110

105111
# 视频预览区域
106112
self.video_display.setObjectName('videoDisplay')
107-
black_layout.addWidget(self.video_display, 0, Qt.AlignCenter)
108-
113+
# black_layout.addWidget(self.video_display, 0, Qt.AlignCenter)
114+
# 创建一个容器来保持比例
115+
ratio_container = QWidget()
116+
ratio_layout = QVBoxLayout(ratio_container)
117+
ratio_layout.setContentsMargins(0, 0, 0, 0)
118+
ratio_layout.addWidget(self.video_display)
119+
120+
# 设置固定的宽高比
121+
ratio_container.setFixedHeight(ratio_container.width() * 9 // 16)
122+
ratio_container.setMinimumWidth(self.video_preview_width)
123+
124+
# 添加到布局
125+
black_layout.addWidget(ratio_container)
126+
127+
# 添加一个事件过滤器来处理大小变化
128+
class RatioEventFilter(QObject):
129+
def eventFilter(self, obj, event):
130+
if event.type() == QEvent.Resize:
131+
obj.setFixedHeight(obj.width() * 9 // 16)
132+
return False
133+
134+
ratio_filter = RatioEventFilter(ratio_container)
135+
ratio_container.installEventFilter(ratio_filter)
136+
109137
# 进度条和滑块容器
110138
control_container = QWidget(self)
111139
control_layout = QVBoxLayout()
@@ -125,7 +153,13 @@ def __initWidget(self):
125153
self.video_container.setLayout(video_layout)
126154
main_layout.addWidget(self.video_container)
127155

128-
def update_video_display(self, frame):
156+
def update_video_display(self, frame, draw_selection=True):
157+
"""更新视频显示"""
158+
if frame is None:
159+
return
160+
161+
# 调整视频帧大小以适应视频预览区域
162+
frame = cv2.resize(frame, (self.video_preview_width, self.video_preview_height))
129163
# 将 OpenCV 帧(BGR 格式)转换为 QImage 并显示在 QLabel 上
130164
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
131165
h, w, ch = rgb_frame.shape
@@ -139,6 +173,7 @@ def update_video_display(self, frame):
139173

140174
painter = QtGui.QPainter(rounded_pix)
141175
painter.setRenderHint(QtGui.QPainter.Antialiasing) # 抗锯齿
176+
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
142177

143178
# 创建圆角路径
144179
path = QtGui.QPainterPath()
@@ -165,7 +200,7 @@ def update_video_display(self, frame):
165200
self.video_display.setPixmap(rounded_pix)
166201

167202
# 如果有保存的选择框比例,根据新视频尺寸重新计算选择框
168-
if self.selection_ratio is not None and self.scaled_width and self.scaled_height:
203+
if draw_selection and self.selection_ratio is not None and self.scaled_width and self.scaled_height:
169204
x_ratio, y_ratio, w_ratio, h_ratio = self.selection_ratio
170205

171206
# 计算新的选择框坐标和大小
@@ -207,12 +242,37 @@ def update_preview_with_rect(self, rect=None):
207242

208243
def selection_mouse_press(self, event):
209244
"""鼠标按下事件处理"""
245+
if not self.enable_mouse_events:
246+
return
210247
pos = event.pos()
248+
249+
# 检测双击或三击,重置选择框
250+
if event.type() == QtCore.QEvent.MouseButtonDblClick:
251+
self.selection_rect = QRect(pos, pos)
252+
self.resize_edge = None
253+
self.is_drawing = True
254+
self.drag_start_pos = pos
255+
return
211256

212257
# 检查是否在选择框边缘(用于调整大小)
213258
if self.selection_rect.isValid():
259+
# 右下角
260+
if abs(pos.x() - self.selection_rect.right()) <= self.edge_size and abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size:
261+
self.resize_edge = "bottomright"
262+
self.drag_start_pos = pos
263+
return
264+
# 右上角
265+
elif abs(pos.x() - self.selection_rect.right()) <= self.edge_size and abs(pos.y() - self.selection_rect.top()) <= self.edge_size:
266+
self.resize_edge = "topright"
267+
self.drag_start_pos = pos
268+
return
269+
# 左下角
270+
elif abs(pos.x() - self.selection_rect.left()) <= self.edge_size and abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size:
271+
self.resize_edge = "bottomleft"
272+
self.drag_start_pos = pos
273+
return
214274
# 左边缘
215-
if abs(pos.x() - self.selection_rect.left()) <= self.edge_size and self.selection_rect.top() <= pos.y() <= self.selection_rect.bottom():
275+
elif abs(pos.x() - self.selection_rect.left()) <= self.edge_size and self.selection_rect.top() <= pos.y() <= self.selection_rect.bottom():
216276
self.resize_edge = "left"
217277
self.drag_start_pos = pos
218278
return
@@ -236,21 +296,6 @@ def selection_mouse_press(self, event):
236296
self.resize_edge = "topleft"
237297
self.drag_start_pos = pos
238298
return
239-
# 右上角
240-
elif abs(pos.x() - self.selection_rect.right()) <= self.edge_size and abs(pos.y() - self.selection_rect.top()) <= self.edge_size:
241-
self.resize_edge = "topright"
242-
self.drag_start_pos = pos
243-
return
244-
# 左下角
245-
elif abs(pos.x() - self.selection_rect.left()) <= self.edge_size and abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size:
246-
self.resize_edge = "bottomleft"
247-
self.drag_start_pos = pos
248-
return
249-
# 右下角
250-
elif abs(pos.x() - self.selection_rect.right()) <= self.edge_size and abs(pos.y() - self.selection_rect.bottom()) <= self.edge_size:
251-
self.resize_edge = "bottomright"
252-
self.drag_start_pos = pos
253-
return
254299
# 在选择框内部(用于移动)
255300
elif self.selection_rect.contains(pos):
256301
self.resize_edge = "move"
@@ -265,6 +310,8 @@ def selection_mouse_press(self, event):
265310

266311
def selection_mouse_move(self, event):
267312
"""鼠标移动事件处理"""
313+
if not self.enable_mouse_events:
314+
return
268315
pos = event.pos()
269316

270317
# 根据不同的操作模式处理鼠标移动
@@ -276,7 +323,40 @@ def selection_mouse_move(self, event):
276323
# 移动整个选择框
277324
dx = pos.x() - self.drag_start_pos.x()
278325
dy = pos.y() - self.drag_start_pos.y()
279-
self.selection_rect.translate(dx, dy)
326+
327+
# 保存原始选择框尺寸
328+
original_width = self.selection_rect.width()
329+
original_height = self.selection_rect.height()
330+
331+
# 计算新位置
332+
new_rect = self.selection_rect.translated(dx, dy)
333+
334+
# 获取视频显示区域
335+
display_rect = self.video_display.rect()
336+
337+
# 检查是否超出边界,如果超出则调整位置但保持尺寸
338+
if new_rect.left() < 0:
339+
new_rect.moveLeft(0)
340+
if new_rect.top() < 0:
341+
new_rect.moveTop(0)
342+
if new_rect.right() > display_rect.width():
343+
new_rect.moveRight(display_rect.width())
344+
if new_rect.bottom() > display_rect.height():
345+
new_rect.moveBottom(display_rect.height())
346+
347+
# 确保尺寸不变
348+
if new_rect.width() != original_width or new_rect.height() != original_height:
349+
# 如果尺寸变了,恢复原始尺寸
350+
if new_rect.left() == 0:
351+
new_rect.setWidth(original_width)
352+
if new_rect.top() == 0:
353+
new_rect.setHeight(original_height)
354+
if new_rect.right() == display_rect.width():
355+
new_rect.setLeft(new_rect.right() - original_width)
356+
if new_rect.bottom() == display_rect.height():
357+
new_rect.setTop(new_rect.bottom() - original_height)
358+
359+
self.selection_rect = new_rect
280360
self.drag_start_pos = pos
281361
else:
282362
# 调整选择框大小
@@ -288,25 +368,27 @@ def selection_mouse_move(self, event):
288368
self.selection_rect.setTop(pos.y())
289369
if "bottom" in self.resize_edge:
290370
self.selection_rect.setBottom(pos.y())
291-
292-
# 确保选择框在视频显示区域内
293-
display_rect = self.video_display.rect()
294-
if self.selection_rect.left() < 0:
295-
self.selection_rect.setLeft(0)
296-
if self.selection_rect.top() < 0:
297-
self.selection_rect.setTop(0)
298-
if self.selection_rect.right() > display_rect.width():
299-
self.selection_rect.setRight(display_rect.width())
300-
if self.selection_rect.bottom() > display_rect.height():
301-
self.selection_rect.setBottom(display_rect.height())
302371

372+
# 确保选择框在视频显示区域内
373+
display_rect = self.video_display.rect()
374+
if self.selection_rect.left() < 0:
375+
self.selection_rect.setLeft(0)
376+
if self.selection_rect.top() < 0:
377+
self.selection_rect.setTop(0)
378+
if self.selection_rect.right() > display_rect.width():
379+
self.selection_rect.setRight(display_rect.width())
380+
if self.selection_rect.bottom() > display_rect.height():
381+
self.selection_rect.setBottom(display_rect.height())
382+
303383
self.update_preview_with_rect()
304384
else:
305385
# 更新鼠标指针形状
306386
self.update_cursor_shape(pos)
307387

308388
def selection_mouse_release(self, event):
309389
"""鼠标释放事件处理"""
390+
if not self.enable_mouse_events:
391+
return
310392
# 结束绘制或调整
311393
self.is_drawing = False
312394
self.resize_edge = None
@@ -390,7 +472,18 @@ def load_selection_ratio(self):
390472
# 检查配置值是否有效
391473
if x_ratio is None or y_ratio is None or w_ratio is None or h_ratio is None:
392474
return False
393-
475+
476+
# 检查配置值是否在有效范围内
477+
if w_ratio <= 0.01 or h_ratio <= 0.005:
478+
config.set(config.subtitleSelectionAreaX, config.subtitleSelectionAreaX.defaultValue)
479+
config.set(config.subtitleSelectionAreaY, config.subtitleSelectionAreaY.defaultValue)
480+
config.set(config.subtitleSelectionAreaW, config.subtitleSelectionAreaW.defaultValue)
481+
config.set(config.subtitleSelectionAreaH, config.subtitleSelectionAreaH.defaultValue)
482+
x_ratio = config.subtitleSelectionAreaX.value
483+
y_ratio = config.subtitleSelectionAreaY.value
484+
w_ratio = config.subtitleSelectionAreaW.value
485+
h_ratio = config.subtitleSelectionAreaH.value
486+
394487
# 保存选择框比例
395488
self.selection_ratio = (x_ratio, y_ratio, w_ratio, h_ratio)
396489

@@ -464,4 +557,10 @@ def get_original_coordinates(self):
464557
ymin = max(0, min(ymin, self.frame_height))
465558
ymax = max(0, min(ymax, self.frame_height))
466559

467-
return (ymin, ymax, xmin, xmax)
560+
return (ymin, ymax, xmin, xmax)
561+
562+
def set_dragger_enabled(self, enabled):
563+
"""设置拖动器是否可用"""
564+
self.enable_mouse_events = enabled
565+
self.video_display.setMouseTracking(enabled)
566+
self.video_display.setCursor(Qt.ArrowCursor)

0 commit comments

Comments
 (0)