Refactor all magic numbers to constants

Introduce constants for brightness and contrast limits, JPEG quality, and frame difference detection thresholds. Refactor related logic to utilize these constants, improving maintainability and consistency across video editing functionalities. Update UI display settings for better text scaling and overlay transparency.
This commit is contained in:
2025-12-23 09:10:42 +01:00
parent 0dc724405b
commit 914ae29073

View File

@@ -758,7 +758,7 @@ class VideoEditor:
# Crop adjustment settings
CROP_SIZE_STEP = 5 # pixels to expand/contract crop
CROP_MIN_SIZE = 10 # minimum crop width/height in pixels
CROP_BORDER_DETECTION_MAX_DISTANCE = 800 # pixels - maximum distance for border hit detection
CROP_BORDER_DETECTION_MAX_DISTANCE = 8000 # pixels - maximum distance for border hit detection
# Motion tracking settings
TRACKING_POINT_THRESHOLD = 10 # pixels for delete/snap radius
@@ -768,6 +768,37 @@ class VideoEditor:
SEEK_FRAMES_SHIFT = 10 # Shift modifier: 10 frames
SEEK_FRAMES_DEFAULT = 1 # Default: 1 frame
# Brightness and contrast settings
MIN_BRIGHTNESS = -100
MAX_BRIGHTNESS = 100
MIN_CONTRAST = 0.1
MAX_CONTRAST = 3.0
# Image/video quality settings
JPEG_QUALITY = 95 # JPEG quality for screenshots (0-100)
IMAGE_MODE_FPS = 30 # Dummy FPS for image mode
HIGH_FPS_THRESHOLD = 60 # FPS threshold for high FPS detection
# Frame difference detection settings
FRAME_DIFFERENCE_THRESHOLD_DEFAULT = 10.0 # Percentage threshold for frame difference
FRAME_DIFFERENCE_GAP_DEFAULT = 10 # Number of frames between comparisons
FRAME_DIFFERENCE_PIXEL_THRESHOLD = 30 # Pixel threshold for binary thresholding
# Template matching settings
TEMPLATE_MATCH_HISTORY_SIZE = 20 # Number of recent matches to keep
TEMPLATE_MATCH_AVERAGE_SIZE = 10 # Number of recent matches for average calculation
TEMPLATE_MATCH_MIN_THRESHOLD = 0.3 # Minimum confidence threshold
TEMPLATE_MATCH_AVERAGE_FACTOR = 0.8 # Factor for adaptive threshold (80% of average)
TEMPLATE_MATCH_DEFAULT_THRESHOLD = 0.5 # Default confidence threshold
# Search/update intervals
INTERESTING_POINT_SEARCH_UPDATE_INTERVAL = 10 # Frames between progress updates
# UI display settings
FONT_SCALE_SMALL = 0.5 # Small font scale for UI text
OVERLAY_ALPHA_LOW = 0.3 # Low alpha for transparent overlays
OVERLAY_ALPHA_HIGH = 0.7 # High alpha for semi-transparent overlays
def __init__(self, path: str):
self.path = Path(path)
@@ -894,8 +925,8 @@ class VideoEditor:
self.template_matching_full_frame = False # Toggle for full frame vs cropped template matching
# Frame difference for interesting point detection
self.frame_difference_threshold = 10.0 # Percentage threshold for frame difference (10% default)
self.frame_difference_gap = 10 # Number of frames between comparisons (default 10)
self.frame_difference_threshold = self.FRAME_DIFFERENCE_THRESHOLD_DEFAULT
self.frame_difference_gap = self.FRAME_DIFFERENCE_GAP_DEFAULT
# Region selection for interesting point detection
self.interesting_region = None # (x, y, width, height) or None for full frame
@@ -1108,8 +1139,8 @@ class VideoEditor:
# Validate and clamp values
self.current_frame = max(0, min(self.current_frame, getattr(self, 'total_frames', 1) - 1))
self.zoom_factor = max(self.MIN_ZOOM, min(self.MAX_ZOOM, self.zoom_factor))
self.brightness = max(-100, min(100, self.brightness))
self.contrast = max(0.1, min(3.0, self.contrast))
self.brightness = max(self.MIN_BRIGHTNESS, min(self.MAX_BRIGHTNESS, self.brightness))
self.contrast = max(self.MIN_CONTRAST, min(self.MAX_CONTRAST, self.contrast))
self.playback_speed = max(self.MIN_PLAYBACK_SPEED, min(self.MAX_PLAYBACK_SPEED, self.playback_speed))
self.seek_multiplier = max(self.MIN_SEEK_MULTIPLIER, min(self.MAX_SEEK_MULTIPLIER, self.seek_multiplier))
@@ -1173,8 +1204,7 @@ class VideoEditor:
if processed_frame is not None:
# Save the processed frame with high quality settings
# Use JPEG quality 95 (0-100, where 100 is highest quality)
success = cv2.imwrite(str(screenshot_path), processed_frame, [cv2.IMWRITE_JPEG_QUALITY, 95])
success = cv2.imwrite(str(screenshot_path), processed_frame, [cv2.IMWRITE_JPEG_QUALITY, self.JPEG_QUALITY])
if success:
print(f"Screenshot saved: {screenshot_name}")
self.show_feedback_message(f"Screenshot saved: {screenshot_name}")
@@ -1236,7 +1266,7 @@ class VideoEditor:
# Set up image properties to mimic video interface
self.frame_height, self.frame_width = self.static_image.shape[:2]
self.total_frames = 1
self.fps = 30 # Dummy FPS for image mode
self.fps = self.IMAGE_MODE_FPS
self.cap = None
print(f"Loaded image: {self.video_path.name}")
@@ -1285,7 +1315,7 @@ class VideoEditor:
print(" Warning: Large H.264 video detected - seeking may be slow")
if self.frame_width * self.frame_height > 1920 * 1080:
print(" Warning: High resolution video - decoding may be slow")
if self.fps > 60:
if self.fps > self.HIGH_FPS_THRESHOLD:
print(" Warning: High framerate video - may impact playback smoothness")
# Set default values for video-specific properties
@@ -1619,7 +1649,7 @@ class VideoEditor:
'base_frame': None,
'base_frame_num': None,
'search_cancelled': False,
'update_interval': 10
'update_interval': self.INTERESTING_POINT_SEARCH_UPDATE_INTERVAL
}
# Enable search mode for OSD display
@@ -1841,7 +1871,7 @@ class VideoEditor:
# Calculate percentage of pixels that changed significantly
# Use threshold to ignore minor noise
_, thresh_diff = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
_, thresh_diff = cv2.threshold(diff, self.FRAME_DIFFERENCE_PIXEL_THRESHOLD, 255, cv2.THRESH_BINARY)
# Count changed pixels
changed_pixels = cv2.countNonZero(thresh_diff)
@@ -2639,16 +2669,16 @@ class VideoEditor:
# Adaptive thresholding based on recent match history
if len(self.template_match_history) > 0:
# Use average of recent matches as baseline
avg_confidence = sum(self.template_match_history[-10:]) / len(self.template_match_history[-10:])
threshold = max(0.3, avg_confidence * 0.8) # 80% of recent average, minimum 0.3
avg_confidence = sum(self.template_match_history[-self.TEMPLATE_MATCH_AVERAGE_SIZE:]) / len(self.template_match_history[-self.TEMPLATE_MATCH_AVERAGE_SIZE:])
threshold = max(self.TEMPLATE_MATCH_MIN_THRESHOLD, avg_confidence * self.TEMPLATE_MATCH_AVERAGE_FACTOR)
else:
threshold = 0.5 # Default threshold
threshold = self.TEMPLATE_MATCH_DEFAULT_THRESHOLD
# Only accept matches above adaptive threshold
if best_confidence > threshold:
# Store confidence for adaptive thresholding
self.template_match_history.append(best_confidence)
if len(self.template_match_history) > 20: # Keep only last 20 matches
if len(self.template_match_history) > self.TEMPLATE_MATCH_HISTORY_SIZE:
self.template_match_history.pop(0)
return best_match
else:
@@ -2879,13 +2909,13 @@ class VideoEditor:
def adjust_brightness(self, delta: int):
"""Adjust brightness by delta (-100 to 100)"""
self.brightness = max(-100, min(100, self.brightness + delta))
self.brightness = max(self.MIN_BRIGHTNESS, min(self.MAX_BRIGHTNESS, self.brightness + delta))
self.clear_transformation_cache()
self.display_needs_update = True
def adjust_contrast(self, delta: float):
"""Adjust contrast by delta (0.1 to 3.0)"""
self.contrast = max(0.1, min(3.0, self.contrast + delta))
self.contrast = max(self.MIN_CONTRAST, min(self.MAX_CONTRAST, self.contrast + delta))
self.clear_transformation_cache()
self.display_needs_update = True
@@ -3038,7 +3068,7 @@ class VideoEditor:
# Semi-transparent background
overlay = frame.copy()
cv2.rectangle(overlay, (rect_x1, rect_y1), (rect_x2, rect_y2), (0, 0, 0), -1)
alpha = 0.7
alpha = self.OVERLAY_ALPHA_HIGH
cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0, frame)
# Draw text with shadow
@@ -3117,12 +3147,12 @@ class VideoEditor:
# Draw progress percentage on the left
percentage_text = f"{self.progress_bar_progress * 100:.1f}%"
text_color = tuple(int(255 * fade_alpha) for _ in range(3))
cv2.putText(
cv2.putText(
frame,
percentage_text,
(bar_x + 12, bar_y + 22),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
self.FONT_SCALE_SMALL,
(0, 0, 0),
4,
)
@@ -3131,7 +3161,7 @@ class VideoEditor:
percentage_text,
(bar_x + 10, bar_y + 20),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
self.FONT_SCALE_SMALL,
text_color,
2,
)
@@ -3139,7 +3169,7 @@ class VideoEditor:
# Draw FPS on the right if available
if self.progress_bar_fps > 0:
fps_text = f"{self.progress_bar_fps:.1f} FPS"
fps_text_size = cv2.getTextSize(fps_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[
fps_text_size = cv2.getTextSize(fps_text, cv2.FONT_HERSHEY_SIMPLEX, self.FONT_SCALE_SMALL, 1)[
0
]
fps_x = bar_x + bar_width - fps_text_size[0] - 10
@@ -3148,7 +3178,7 @@ class VideoEditor:
fps_text,
(fps_x + 2, bar_y + 22),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
self.FONT_SCALE_SMALL,
(0, 0, 0),
4,
)
@@ -3157,7 +3187,7 @@ class VideoEditor:
fps_text,
(fps_x, bar_y + 20),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
self.FONT_SCALE_SMALL,
text_color,
2,
)
@@ -3165,7 +3195,7 @@ class VideoEditor:
# Draw main text in center
if self.progress_bar_text:
text_size = cv2.getTextSize(
self.progress_bar_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1
self.progress_bar_text, cv2.FONT_HERSHEY_SIMPLEX, self.FONT_SCALE_SMALL, 1
)[0]
text_x = bar_x + (bar_width - text_size[0]) // 2
text_y = bar_y + 20
@@ -3570,7 +3600,7 @@ class VideoEditor:
cv2.circle(canvas, (sx, sy), 8, (255, 255, 255), 2)
# Draw confidence text
conf_text = f"{confidence:.2f}"
cv2.putText(canvas, conf_text, (sx + 10, sy - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
cv2.putText(canvas, conf_text, (sx + 10, sy - 10), cv2.FONT_HERSHEY_SIMPLEX, self.FONT_SCALE_SMALL, (255, 255, 255), 1)
# Draw selection rectangles for feature extraction/deletion
@@ -3628,7 +3658,7 @@ class VideoEditor:
cv2.line(overlay, (sx2, sy2), (arrow_x1, arrow_y1), (255, 255, 0), 1)
cv2.line(overlay, (sx2, sy2), (arrow_x2, arrow_y2), (255, 255, 0), 1)
cv2.addWeighted(overlay, 0.3, canvas, 0.7, 0, canvas) # Very transparent
cv2.addWeighted(overlay, self.OVERLAY_ALPHA_LOW, canvas, self.OVERLAY_ALPHA_HIGH, 0, canvas)
# Previous tracking point (red) - from the most recent frame with tracking points before current
if prev_result:
@@ -3689,7 +3719,7 @@ class VideoEditor:
# Semi-transparent background
overlay = canvas.copy()
cv2.rectangle(overlay, (bg_x, bg_y), (bg_x + bg_w, bg_y + bg_h), (0, 0, 0), -1)
cv2.addWeighted(overlay, 0.7, canvas, 0.3, 0, canvas)
cv2.addWeighted(overlay, self.OVERLAY_ALPHA_HIGH, canvas, self.OVERLAY_ALPHA_LOW, 0, canvas)
# Border
cv2.rectangle(canvas, (bg_x, bg_y), (bg_x + bg_w, bg_y + bg_h), (255, 255, 0), 2)
@@ -3749,7 +3779,7 @@ class VideoEditor:
# Draw selection info
info_text = f"Region: {sel_w}x{sel_h}"
cv2.putText(canvas, info_text, (sel_x, sel_y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 1)
cv2.putText(canvas, info_text, (sel_x, sel_y - 5), cv2.FONT_HERSHEY_SIMPLEX, self.FONT_SCALE_SMALL, (0, 255, 255), 1)
window_title = "Image Editor" if self.is_image_mode else "Video Editor"
cv2.imshow(window_title, canvas)
@@ -4639,7 +4669,7 @@ class VideoEditor:
if processed_image is not None:
# Save the image with high quality settings
success = cv2.imwrite(output_path, processed_image, [cv2.IMWRITE_JPEG_QUALITY, 95])
success = cv2.imwrite(output_path, processed_image, [cv2.IMWRITE_JPEG_QUALITY, self.JPEG_QUALITY])
if success:
print(f"Image saved successfully to {output_path}")
return True
@@ -5193,7 +5223,7 @@ class VideoEditor:
print(f"Frame difference threshold: {self.frame_difference_threshold:.1f}% (-10pp)")
self.show_feedback_message(f"Threshold: {self.frame_difference_threshold:.1f}% (-10pp)")
elif key == ord("="): # Shift+0 - Increase frame difference threshold by 10 percentage points
self.frame_difference_threshold = min(100.0, self.frame_difference_threshold + 10.0)
self.frame_difference_threshold = min(100.0, self.frame_difference_threshold + 10.0) # Max 100%
print(f"Frame difference threshold: {self.frame_difference_threshold:.1f}% (+10pp)")
self.show_feedback_message(f"Threshold: {self.frame_difference_threshold:.1f}% (+10pp)")
elif key == ord("7"): # 7 - Decrease frame difference gap