Spaces:
Sleeping
Sleeping
| from flask import Flask, request, send_file | |
| import cv2 | |
| import numpy as np | |
| import tensorflow as tf | |
| from io import BytesIO | |
| from PIL import Image | |
| import os | |
| os.environ["CUDA_VISIBLE_DEVICES"] = "-1" | |
| app = Flask(__name__) | |
| # Ping API Route | |
| def ping(): | |
| return 'Ping from Python API!' | |
| def send_image_response(image, filename="image.jpg"): | |
| """Helper function to return image response""" | |
| _, img_encoded = cv2.imencode('.jpg', image) | |
| img_bytes = img_encoded.tobytes() | |
| buffer = BytesIO(img_bytes) | |
| buffer.seek(0) | |
| # Set Cache-Control headers to prevent caching | |
| response = send_file(buffer, mimetype='image/jpeg', as_attachment=True, download_name=filename) | |
| response.cache_control.no_cache = True | |
| response.cache_control.no_store = True | |
| response.cache_control.must_revalidate = True | |
| response.headers['Pragma'] = 'no-cache' | |
| response.headers['Expires'] = '0' | |
| return response | |
| def before_request(): | |
| """Reset or cleanup any global state before processing each request.""" | |
| # Any necessary cleanup can be done here (e.g., reset global variables). | |
| pass | |
| def after_request(response): | |
| """Perform cleanup after each request if necessary.""" | |
| # Post-request cleanup, if needed, can be done here (e.g., free resources). | |
| return response | |
| # Pencil Sketch API Route | |
| def sketch_image(): | |
| if 'image' not in request.files: | |
| return "No image part", 400 | |
| file = request.files['image'] | |
| img_array = np.frombuffer(file.read(), np.uint8) | |
| image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) | |
| gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
| inverted_image = 255 - gray_image | |
| blurred_image = cv2.GaussianBlur(inverted_image, (111, 111), 0) | |
| inverted_blurred = 255 - blurred_image | |
| sketch = cv2.divide(gray_image, inverted_blurred, scale=256.0) | |
| return send_image_response(sketch, "sketch.jpg") | |
| # Sharpened Pencil Sketch API Route | |
| def sharpened_sketch_image(): | |
| if 'image' not in request.files: | |
| return "No image part", 400 | |
| file = request.files['image'] | |
| img_array = np.frombuffer(file.read(), np.uint8) | |
| image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) | |
| gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
| inverted_image = 255 - gray_image | |
| blurred_image = cv2.GaussianBlur(inverted_image, (21, 21), 0) | |
| inverted_blurred = 255 - blurred_image | |
| sketch = cv2.divide(gray_image, inverted_blurred, scale=256.0) | |
| sharpen_kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]]) | |
| sharpened_sketch = cv2.filter2D(sketch, -1, sharpen_kernel) | |
| return send_image_response(sharpened_sketch, "sharpened_sketch.jpg") | |
| # Anime-style effect API Route | |
| def anime_effect_image(): | |
| if 'image' not in request.files: | |
| return "No image part", 400 | |
| file = request.files['image'] | |
| img_array = np.frombuffer(file.read(), np.uint8) | |
| image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) | |
| bilateral_filtered = cv2.bilateralFilter(image, d=9, sigmaColor=300, sigmaSpace=300) | |
| gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
| gray = cv2.medianBlur(gray, 5) | |
| edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 10) | |
| data = np.float32(image).reshape((-1, 3)) | |
| criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) | |
| k = 8 | |
| _, labels, centers = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) | |
| centers = np.uint8(centers) | |
| quantized_image = centers[labels.flatten()] | |
| quantized_image = quantized_image.reshape(image.shape) | |
| cartoon = cv2.bitwise_and(bilateral_filtered, bilateral_filtered, mask=edges) | |
| anime_image = cv2.bitwise_and(quantized_image, cartoon) | |
| return send_image_response(anime_image, "anime_effect.jpg") | |
| # Cartoon Effect API Route | |
| def cartoon_effect_image(): | |
| if 'image' not in request.files: | |
| return "No image part", 400 | |
| file = request.files['image'] | |
| img_array = np.frombuffer(file.read(), np.uint8) | |
| image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) | |
| gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
| bilateral_image = cv2.bilateralFilter(image, d=9, sigmaColor=75, sigmaSpace=75) | |
| edges = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9) | |
| edges_colored = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) | |
| cartoon_image = cv2.bitwise_and(bilateral_image, edges_colored) | |
| return send_image_response(cartoon_image, "cartoon_effect.jpg") | |
| # Cartoon Conversion API Route | |
| def cartoon_convert(): | |
| if 'image' not in request.files: | |
| return "No image part", 400 | |
| file = request.files['image'] | |
| img_array = np.frombuffer(file.read(), np.uint8) | |
| image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) | |
| model_path = '/app/1.tflite' | |
| source_img = load_image_from_bytes(img_array) | |
| if source_img is None: | |
| return "Error loading image", 400 | |
| processed_img = preprocess_image(source_img) | |
| try: | |
| interpreter = tf.lite.Interpreter(model_path=model_path) | |
| input_details = interpreter.get_input_details() | |
| interpreter.allocate_tensors() | |
| interpreter.set_tensor(input_details[0]['index'], processed_img) | |
| interpreter.invoke() | |
| result = interpreter.tensor(interpreter.get_output_details()[0]['index'])() | |
| except Exception as e: | |
| return f"Error during model inference: {e}", 500 | |
| output = post_process(result, preserve_details=True) | |
| output_image = Image.fromarray(output) | |
| img_bytes = BytesIO() | |
| output_image.save(img_bytes, format='JPEG') | |
| img_bytes.seek(0) | |
| # Set Cache-Control headers to prevent caching | |
| response = send_file(img_bytes, mimetype='image/jpeg', as_attachment=True, download_name='cartoon_converted_image.jpg') | |
| response.cache_control.no_cache = True | |
| response.cache_control.no_store = True | |
| response.cache_control.must_revalidate = True | |
| response.headers['Pragma'] = 'no-cache' | |
| response.headers['Expires'] = '0' | |
| return response | |
| # Helper Functions for Cartoon Conversion | |
| def load_image_from_bytes(img_bytes): | |
| try: | |
| img = cv2.imdecode(np.frombuffer(img_bytes, np.uint8), cv2.IMREAD_COLOR) | |
| if img is None: | |
| raise ValueError("Failed to load image") | |
| img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
| img = img.astype(np.float32) / 127.5 - 1 | |
| img = np.expand_dims(img, 0) | |
| return tf.convert_to_tensor(img) | |
| except Exception as e: | |
| print(f"Error loading image: {e}") | |
| return None | |
| def preprocess_image(img, target_dim=512): | |
| shape = tf.cast(tf.shape(img)[1:-1], tf.float32) | |
| min_dim = tf.reduce_min(shape) | |
| scale = target_dim / min_dim | |
| new_shape = tf.cast(shape * scale, tf.int32) | |
| img = tf.image.resize(img, new_shape, method='area') | |
| img = tf.image.resize_with_crop_or_pad(img, target_dim, target_dim) | |
| return img | |
| def apply_detail_preserving_smoothing(img): | |
| smooth = cv2.detailEnhance(img, sigma_s=10, sigma_r=0.15) | |
| smooth = cv2.edgePreservingFilter(smooth, flags=1, sigma_s=60, sigma_r=0.4) | |
| return smooth | |
| def enhance_colors(img): | |
| lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB) | |
| l, a, b = cv2.split(lab) | |
| clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) | |
| l = clahe.apply(l) | |
| lab = cv2.merge((l,a,b)) | |
| enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) | |
| return enhanced | |
| def post_process(output, preserve_details=True): | |
| img = (np.squeeze(output) + 1.0) * 127.5 | |
| img = np.clip(img, 0, 255).astype(np.uint8) | |
| if preserve_details: | |
| img = apply_detail_preserving_smoothing(img) | |
| img = enhance_colors(img) | |
| img = cv2.bilateralFilter(img, 5, 35, 35) | |
| return img | |
| if __name__ == '__main__': | |
| app.run(debug=True, host="0.0.0.0", port=7860) | |