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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user