Spaces:
Sleeping
Sleeping
# author : OzlemAkgunoglu | |
# github : https://github.com/OzlemAkgunoglu | |
# Dynamic Photo Filter App | |
# This is a Dynamic Photo Filter App that allows you to apply various filters to your images. | |
# Adjust brightness, contrast, sharpening, and select a filter for real-time changes. | |
# And this app is created using OpenCV and Gradio. Thank you for using it. | |
# Let's load the necessary libraries | |
import cv2 as cv # OpenCV for image processing | |
import numpy as np # Numpy for arrays | |
import gradio as gr # Gradio for UI | |
import re | |
def rgba_to_rgb(rgba_string): | |
match = re.match(r'rgba\(([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)\)', rgba_string) | |
if not match: | |
raise ValueError("Invalid RGBA") | |
r, g, b, a = map(float, match.groups()) | |
return (int(r), int(g), int(b)) | |
# Let's define the filter functions | |
def apply_grayscale(image): | |
return cv.cvtColor(image, cv.COLOR_BGR2GRAY) # Convert the image to grayscale | |
# Sepia filter function | |
def apply_sepia(image): | |
sepia_filter = np.array([[0.272, 0.534, 0.131], | |
[0.349, 0.686, 0.168], | |
[0.393, 0.769, 0.189]]) | |
sepia_image = cv.transform(image, sepia_filter) # Apply the filter | |
return np.clip(sepia_image, 0, 255).astype(np.uint8) # clip to hold values between 0 and 255 prevent excessive brightness or darkening. | |
def apply_negative(image): | |
return cv.bitwise_not(image) # Invert the image | |
# Sketch filter | |
def apply_sketch(image): | |
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) # Convert the image to grayscale | |
inv = cv.bitwise_not(gray) # Invert the grayscale image | |
blurred = cv.GaussianBlur(inv, (21, 21), sigmaX=0, sigmaY=0) | |
sketch_image = cv.divide(gray, 255 - blurred, scale=256) | |
return sketch_image | |
def apply_sharpen(image, sharpening): | |
sharpening_filter = np.array([[0, -1, 0], | |
[-1, 5 + sharpening, -1], | |
[0, -1, 0]]) | |
return cv.filter2D(image, -1, sharpening_filter) # Apply the filter each pixel is multiplied by the value in the kernel | |
def apply_edge_detection(image): | |
return cv.Canny(image, 100, 200) | |
def apply_fall_filter(frame): | |
fall_filter = np.array([[0.393, 0.769, 0.189], | |
[0.349, 0.686, 0.168], | |
[0.272, 0.534, 0.131]]) | |
return cv.transform(frame, fall_filter) | |
# Emboss filter | |
def apply_emboss(image): | |
emboss_filter = np.array([[0, -1, 0], | |
[-1, 5, -1], | |
[0, -1, 0]]) | |
return cv.filter2D(image, -1, emboss_filter) | |
# Blur filter | |
def apply_blur(image, kernel_size): | |
return cv.blur(image, (kernel_size, kernel_size)) | |
# Vintage filter | |
def apply_vintage(image): | |
vintage_filter = np.array([[0.627, 0.554, 0.369], | |
[0.766, 0.714, 0.406], | |
[0.882, 0.869, 0.524]]) | |
vintage_image = cv.transform(image, vintage_filter) # Apply the filter | |
return np.clip(vintage_image, 0, 255).astype(np.uint8) # clip to hold values between 0 and 255 prevent excessive brightness or darkening. | |
# Combined filter | |
def apply_combined(image, sharpening): | |
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) | |
sepia = apply_sepia(image) | |
sharpened = apply_sharpen(sepia, sharpening) | |
edges = apply_edge_detection(gray) | |
edges = cv.cvtColor(edges, cv.COLOR_GRAY2BGR) | |
combined = cv.addWeighted(sharpened, 0.7, edges, 0.3, 0) | |
return combined | |
# Cartoon filter | |
def apply_cartoon(image): | |
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) | |
gray = cv.medianBlur(gray, 7) | |
edges = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY_INV, 9, 9) | |
color = cv.bilateralFilter(image, 9, 300, 300) | |
cartoon = cv.bitwise_and(color, color, mask=edges) | |
return cartoon | |
# Watercolor filter | |
def apply_watercolor(image, size, sigma): | |
blurred = cv.GaussianBlur(image, (size, size), sigma) | |
watercolor = cv.addWeighted(image, 0.5, blurred, 0.5, 0) | |
return watercolor | |
# Hue Shift filter | |
def apply_hue_shift(image, hue_shift): | |
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV) | |
h, s, v = cv.split(hsv) | |
h = cv.add(h, hue_shift) | |
shifted_hsv = cv.merge([h, s, v]) | |
shifted_image = cv.cvtColor(shifted_hsv, cv.COLOR_HSV2BGR) | |
return shifted_image | |
def apply_60s_tv(image): | |
# Convert to sepia | |
sepia = apply_sepia(image) | |
# Reduce sharpness | |
blurred = cv.GaussianBlur(sepia, (5, 5), sigmaX=0, sigmaY=0) | |
# Add noise | |
noise = np.zeros(sepia.shape, dtype=np.int16) | |
cv.randn(noise, 0, 20) | |
noisy_image = cv.add(blurred, noise, dtype=cv.CV_8UC3) | |
noisy_image = np.clip(noisy_image, 0, 255).astype(np.uint8) | |
# Reduce color depth | |
noisy_image = (noisy_image // 32) * 32 | |
return noisy_image | |
# Vignette filter | |
def apply_vignette(image, strength, aspect_ratio, center_x, center_y, radius, smoothness): | |
rows, cols = image.shape[:2] | |
center = (int(cols * center_x), int(rows * center_y)) | |
mask = np.zeros((rows, cols), dtype=np.float32) | |
for i in range(rows): | |
for j in range(cols): | |
distance_x = (j - center[0]) / (cols * aspect_ratio) | |
distance_y = (i - center[1]) / rows | |
distance = np.sqrt(distance_x**2 + distance_y**2) | |
mask[i, j] = 1 - (distance / radius) ** strength | |
mask = np.clip(mask, 0, 1) | |
mask = np.stack((mask, mask, mask), axis=2) | |
vignette_image = cv.multiply(image.astype(np.float32), mask) | |
return vignette_image.astype(np.uint8) | |
# Tint filter | |
def apply_tint(image, tint_color, intensity): | |
tint_color = np.array(tint_color, dtype=np.float32) / 255.0 | |
tint_color = cv.cvtColor(np.uint8([[tint_color]]), cv.COLOR_BGR2HSV).flatten() | |
hsv_image = cv.cvtColor(image, cv.COLOR_BGR2HSV).astype(np.float32) | |
hsv_image[:, :, 0] = (hsv_image[:, :, 0] + tint_color[0] * intensity) % 180 | |
hsv_image[:, :, 1] = np.clip(hsv_image[:, :, 1] + tint_color[1] * intensity, 0, 255) | |
hsv_image[:, :, 2] = np.clip(hsv_image[:, :, 2] + tint_color[2] * intensity, 0, 255) | |
tinted_image = cv.cvtColor(hsv_image.astype(np.uint8), cv.COLOR_HSV2BGR) | |
return tinted_image | |
# Dictionary to map filter names to functions | |
filter_functions = { | |
"Grayscale": apply_grayscale, | |
"Sepia": apply_sepia, | |
"Negative": apply_negative, | |
"Sketch": apply_sketch, | |
"Sharpen": apply_sharpen, | |
"Edge Detection": apply_edge_detection, | |
"Fall": apply_fall_filter, | |
"Emboss": apply_emboss, | |
"Blur": apply_blur, | |
"Vintage": apply_vintage, | |
"Combined": apply_combined, | |
"Cartoon": apply_cartoon, | |
"Watercolor": apply_watercolor, | |
"Hue Shift": apply_hue_shift, | |
"60s TV": apply_60s_tv, | |
"Vignette": apply_vignette, | |
"Tint": apply_tint | |
} | |
# Main function to apply selected filters | |
def apply_filters(image, filter_type, brightness, contrast, sharpening, kernel_size, hue_shift, size, sigma, vignette_strength, vignette_aspect_ratio, vignette_center_x, vignette_center_y, vignette_radius, vignette_smoothness, tint_color, tint_intensity): | |
if image is None: | |
gr.Error("Input image is empty!") # for debugging | |
return None # Return None if the input image is empty | |
# Adjust brightness and contrast | |
image = cv.convertScaleAbs(image, alpha=contrast, beta=brightness) | |
if isinstance(tint_color, str): | |
if tint_color.startswith('#') and len(tint_color) == 7: | |
try: | |
tint_color = tint_color.lstrip('#') | |
tint_color_rgb = tuple(int(tint_color[i:i+2], 16) for i in (0, 2, 4)) | |
except ValueError: | |
print("Invalid hex color format. Using default color #FF0000.") | |
tint_color_rgb = (255, 0, 0) # Default color red | |
elif tint_color.startswith('rgba('): | |
try: | |
tint_color_rgb = rgba_to_rgb(tint_color) | |
except ValueError: | |
print("Invalid rgba format. Using default color #FF0000.", ) | |
tint_color_rgb = (255, 0, 0) # Default color red | |
else: | |
print("Invalid color format. Using default color #FF0000.") | |
tint_color_rgb = (255, 0, 0) # Default color red | |
else: | |
print("Invalid color format. Using default color #FF0000.") | |
tint_color_rgb = (255, 0, 0) # Default color red | |
# Apply the selected filter from dictionary called filter_functions | |
if filter_type in filter_functions: | |
if filter_type == "Sharpen" or filter_type == "Combined": | |
image = filter_functions[filter_type](image, sharpening) # Calls the Sharpen or Combined filter with the sharpening parameter | |
elif filter_type == "Blur": | |
image = filter_functions[filter_type](image, kernel_size) # Calls the Blur filter with the kernel_size parameter | |
elif filter_type == "Hue Shift": | |
image = filter_functions[filter_type](image, hue_shift) # Calls the Hue Shift filter with hue_shift parameter | |
elif filter_type == "Watercolor": | |
image = filter_functions[filter_type](image, size, sigma) # Calls the Watercolor filter with size and sigma parameters | |
elif filter_type == "Vignette": | |
image = filter_functions[filter_type](image, vignette_strength, vignette_aspect_ratio, vignette_center_x, vignette_center_y, vignette_radius, vignette_smoothness) # Calls the Vignette filter with vignette_strength parameter | |
elif filter_type == "Tint": | |
image = filter_functions[filter_type](image, tint_color_rgb, tint_intensity) | |
else: | |
image = filter_functions[filter_type](image) | |
return image | |
# Define Interface | |
with gr.Blocks(theme="ParityError/Interstellar") as app: | |
# Title and Description | |
gr.Markdown("<h1 style='font-family: Arial, sans-serif; color: #333;'>📸 Photo Filter ⭐</h1>") | |
gr.Markdown("<p style='color: #666;'>Apply professional photo filters with adjustable brightness, contrast, and sharpness. Perfect your images instantly!</p>") | |
# Choices and Sliders at the Top | |
with gr.Row(): | |
filter_choice = gr.Radio(list(filter_functions.keys()), label="Filter") | |
with gr.Column(): | |
brightness_slider = gr.Slider(-100, 100, step=1, label="Brightness", value=0) | |
contrast_slider = gr.Slider(0.5, 3.0, step=0.1, label="Contrast", value=1.0) | |
sharpening_slider = gr.Slider(0, 5, step=0.1, label="Sharpening", value=0) | |
blur_slider = gr.Slider(3, 21, step=2, label="Blur Kernel Size", value=15, visible=False) | |
hue_shift_slider = gr.Slider(-180, 180, step=1, label="Hue Shift", value=0, visible=False) | |
watercolor_size_slider = gr.Slider(3, 21, step=2, label="Watercolor Size", value=15, visible=False) | |
watercolor_sigma_slider = gr.Slider(0.1, 10.0, step=0.1, label="Watercolor Sigma", value=2.0, visible=False) | |
vignette_strength_slider = gr.Slider(1, 10, step=0.1, label="Vignette Strength", value=3.0, visible=False) | |
vignette_aspect_ratio_slider = gr.Slider(0.5, 2.0, step=0.1, label="Vignette Aspect Ratio", value=1.0, visible=False) | |
vignette_center_x_slider = gr.Slider(0.0, 1.0, step=0.01, label="Vignette Center X", value=0.5, visible=False) | |
vignette_center_y_slider = gr.Slider(0.0, 1.0, step=0.01, label="Vignette Center Y", value=0.5, visible=False) | |
vignette_radius_slider = gr.Slider(0.1, 1.0, step=0.01, label="Vignette Radius", value=0.75, visible=False) | |
vignette_smoothness_slider = gr.Slider(1, 10, step=0.1, label="Vignette Smoothness", value=3.0, visible=False) | |
tint_color_picker = gr.ColorPicker(label="Tint Color", value="#FF0000", visible=False) | |
tint_intensity_slider = gr.Slider(0, 1, step=0.01, label="Tint Intensity", value=0.5, visible=False) | |
# Horizontal display of the images | |
with gr.Row(): | |
image_input = gr.Image(label="Upload Image", type="numpy") | |
image_output = gr.Image(label="Filtered Image") | |
# Function to update visibility of sliders | |
def update_slider_visibility(filter_type): | |
blur_visible = filter_type == "Blur" | |
hue_visible = filter_type == "Hue Shift" | |
watercolor_visible = filter_type == "Watercolor" | |
vignette_visible = filter_type == "Vignette" | |
tint_visible = filter_type == "Tint" | |
return ( | |
gr.update(visible=blur_visible), | |
gr.update(visible=hue_visible), | |
gr.update(visible=watercolor_visible), | |
gr.update(visible=watercolor_visible), | |
gr.update(visible=vignette_visible), | |
gr.update(visible=vignette_visible), | |
gr.update(visible=vignette_visible), | |
gr.update(visible=vignette_visible), | |
gr.update(visible=vignette_visible), | |
gr.update(visible=vignette_visible), | |
gr.update(visible=tint_visible), | |
gr.update(visible=tint_visible) | |
) | |
# Link events for real-time updates | |
image_input.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
filter_choice.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
brightness_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
contrast_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
sharpening_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
blur_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
hue_shift_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
watercolor_size_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
watercolor_sigma_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
vignette_strength_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
vignette_aspect_ratio_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
vignette_center_x_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
vignette_center_y_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
vignette_radius_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
vignette_smoothness_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
tint_color_picker.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
tint_intensity_slider.change( | |
apply_filters, | |
inputs=[ | |
image_input, filter_choice, brightness_slider, contrast_slider, sharpening_slider, | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
], | |
outputs=image_output | |
) | |
# Update visibility of sliders when filter_choice changes | |
filter_choice.change( | |
update_slider_visibility, | |
inputs=[filter_choice], | |
outputs=[ | |
blur_slider, hue_shift_slider, watercolor_size_slider, watercolor_sigma_slider, | |
vignette_strength_slider, vignette_aspect_ratio_slider, vignette_center_x_slider, | |
vignette_center_y_slider, vignette_radius_slider, vignette_smoothness_slider, | |
tint_color_picker, tint_intensity_slider | |
] | |
) | |
app.launch() |