Add brightness and contrast controls
This commit is contained in:
@@ -83,6 +83,10 @@ class VideoEditor:
|
||||
# Rotation settings
|
||||
self.rotation_angle = 0 # 0, 90, 180, 270 degrees
|
||||
|
||||
# Brightness and contrast settings
|
||||
self.brightness = 0 # -100 to 100
|
||||
self.contrast = 1.0 # 0.1 to 3.0
|
||||
|
||||
# Cut points
|
||||
self.cut_start_frame = None
|
||||
self.cut_end_frame = None
|
||||
@@ -121,12 +125,14 @@ class VideoEditor:
|
||||
self.playback_speed = 1.0
|
||||
self.current_display_frame = None
|
||||
|
||||
# Reset crop, zoom, rotation, and cut settings for new video
|
||||
# Reset crop, zoom, rotation, brightness/contrast, and cut settings for new video
|
||||
self.crop_rect = None
|
||||
self.crop_history = []
|
||||
self.zoom_factor = 1.0
|
||||
self.zoom_center = None
|
||||
self.rotation_angle = 0
|
||||
self.brightness = 0
|
||||
self.contrast = 1.0
|
||||
self.cut_start_frame = None
|
||||
self.cut_end_frame = None
|
||||
self.display_offset = [0, 0]
|
||||
@@ -198,21 +204,24 @@ class VideoEditor:
|
||||
return self.load_current_frame()
|
||||
|
||||
def apply_crop_zoom_and_rotation(self, frame):
|
||||
"""Apply current crop, zoom, and rotation settings to frame"""
|
||||
"""Apply current crop, zoom, rotation, and brightness/contrast settings to frame"""
|
||||
if frame is None:
|
||||
return None
|
||||
|
||||
processed_frame = frame.copy()
|
||||
|
||||
# Apply crop first
|
||||
# Apply brightness/contrast first (to original frame for best quality)
|
||||
processed_frame = self.apply_brightness_contrast(processed_frame)
|
||||
|
||||
# Apply crop
|
||||
if self.crop_rect:
|
||||
x, y, w, h = self.crop_rect
|
||||
x, y, w, h = int(x), int(y), int(w), int(h)
|
||||
# Ensure crop is within frame bounds
|
||||
x = max(0, min(x, frame.shape[1] - 1))
|
||||
y = max(0, min(y, frame.shape[0] - 1))
|
||||
w = min(w, frame.shape[1] - x)
|
||||
h = min(h, frame.shape[0] - y)
|
||||
x = max(0, min(x, processed_frame.shape[1] - 1))
|
||||
y = max(0, min(y, processed_frame.shape[0] - 1))
|
||||
w = min(w, processed_frame.shape[1] - x)
|
||||
h = min(h, processed_frame.shape[0] - y)
|
||||
if w > 0 and h > 0:
|
||||
processed_frame = processed_frame[y:y+h, x:x+w]
|
||||
|
||||
@@ -254,6 +263,26 @@ class VideoEditor:
|
||||
"""Rotate video 90 degrees clockwise"""
|
||||
self.rotation_angle = (self.rotation_angle + 90) % 360
|
||||
|
||||
def apply_brightness_contrast(self, frame):
|
||||
"""Apply brightness and contrast adjustments to frame"""
|
||||
if self.brightness == 0 and self.contrast == 1.0:
|
||||
return frame
|
||||
|
||||
# Convert brightness from -100/100 range to -255/255 range
|
||||
brightness_value = self.brightness * 2.55
|
||||
|
||||
# Apply brightness and contrast: new_pixel = contrast * old_pixel + brightness
|
||||
adjusted = cv2.convertScaleAbs(frame, alpha=self.contrast, beta=brightness_value)
|
||||
return adjusted
|
||||
|
||||
def adjust_brightness(self, delta: int):
|
||||
"""Adjust brightness by delta (-100 to 100)"""
|
||||
self.brightness = max(-100, min(100, self.brightness + delta))
|
||||
|
||||
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))
|
||||
|
||||
def draw_timeline(self, frame):
|
||||
"""Draw timeline at the bottom of the frame"""
|
||||
height, width = frame.shape[:2]
|
||||
@@ -370,7 +399,9 @@ class VideoEditor:
|
||||
|
||||
# Add info overlay
|
||||
rotation_text = f" | Rotation: {self.rotation_angle}°" if self.rotation_angle != 0 else ""
|
||||
info_text = f"Frame: {self.current_frame}/{self.total_frames} | Speed: {self.playback_speed:.1f}x | Zoom: {self.zoom_factor:.1f}x{rotation_text} | {'Playing' if self.is_playing else 'Paused'}"
|
||||
brightness_text = f" | Brightness: {self.brightness}" if self.brightness != 0 else ""
|
||||
contrast_text = f" | Contrast: {self.contrast:.1f}" if self.contrast != 1.0 else ""
|
||||
info_text = f"Frame: {self.current_frame}/{self.total_frames} | Speed: {self.playback_speed:.1f}x | Zoom: {self.zoom_factor:.1f}x{rotation_text}{brightness_text}{contrast_text} | {'Playing' if self.is_playing else 'Paused'}"
|
||||
cv2.putText(canvas, info_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
|
||||
cv2.putText(canvas, info_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 0), 1)
|
||||
|
||||
@@ -648,6 +679,9 @@ class VideoEditor:
|
||||
else:
|
||||
return None
|
||||
|
||||
# Apply brightness and contrast
|
||||
frame = self.apply_brightness_contrast(frame)
|
||||
|
||||
# Apply rotation
|
||||
if self.rotation_angle != 0:
|
||||
frame = self.apply_rotation(frame)
|
||||
@@ -682,6 +716,8 @@ class VideoEditor:
|
||||
print(" Shift+A/D: Seek backward/forward (10 frames)")
|
||||
print(" Ctrl+A/D: Seek backward/forward (60 frames)")
|
||||
print(" W/S: Increase/Decrease speed")
|
||||
print(" E/Shift+E: Increase/Decrease brightness")
|
||||
print(" R/Shift+R: Increase/Decrease contrast")
|
||||
print(" -: Rotate clockwise 90°")
|
||||
print(" Shift+Click+Drag: Select crop area")
|
||||
print(" U: Undo crop")
|
||||
@@ -740,6 +776,22 @@ class VideoEditor:
|
||||
self.playback_speed = min(self.MAX_PLAYBACK_SPEED, self.playback_speed + self.SPEED_INCREMENT)
|
||||
elif key == ord('s'):
|
||||
self.playback_speed = max(self.MIN_PLAYBACK_SPEED, self.playback_speed - self.SPEED_INCREMENT)
|
||||
elif key == ord('e') or key == ord('E'):
|
||||
# Brightness adjustment: E (increase), Shift+E (decrease)
|
||||
if key == ord('E'):
|
||||
self.adjust_brightness(-5)
|
||||
print(f"Brightness: {self.brightness}")
|
||||
else:
|
||||
self.adjust_brightness(5)
|
||||
print(f"Brightness: {self.brightness}")
|
||||
elif key == ord('r') or key == ord('R'):
|
||||
# Contrast adjustment: R (increase), Shift+R (decrease)
|
||||
if key == ord('R'):
|
||||
self.adjust_contrast(-0.1)
|
||||
print(f"Contrast: {self.contrast:.1f}")
|
||||
else:
|
||||
self.adjust_contrast(0.1)
|
||||
print(f"Contrast: {self.contrast:.1f}")
|
||||
elif key == ord('u'):
|
||||
self.undo_crop()
|
||||
elif key == ord('c'):
|
||||
|
Reference in New Issue
Block a user