| """ |
| AI-Enhanced Comic Generation Core |
| High-quality comic generation using modern AI models |
| """ |
|
|
| import cv2 |
| import numpy as np |
| import torch |
| import torch.nn as nn |
| import torchvision.transforms as transforms |
| from PIL import Image, ImageEnhance, ImageFilter |
| import os |
| import json |
| from typing import List, Tuple, Dict, Optional |
| |
| from transformers import pipeline, AutoModelForImageClassification, AutoFeatureExtractor |
| import requests |
| from io import BytesIO |
| import threading |
| import time |
|
|
| class AIEnhancedCore: |
| def __init__(self): |
| self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') |
| |
| |
| try: |
| import mediapipe as mp |
| self.face_mesh = mp.solutions.face_mesh.FaceMesh( |
| static_image_mode=True, |
| max_num_faces=10, |
| refine_landmarks=True, |
| min_detection_confidence=0.5 |
| ) |
| self.pose = mp.solutions.pose.Pose( |
| static_image_mode=True, |
| model_complexity=2, |
| enable_segmentation=True, |
| min_detection_confidence=0.5 |
| ) |
| self.use_mediapipe = True |
| except ImportError: |
| print("⚠️ MediaPipe not available, using fallback methods") |
| self.face_mesh = None |
| self.pose = None |
| self.use_mediapipe = False |
| |
| |
| self._load_ai_models() |
| |
| def _load_ai_models(self): |
| """Load all AI models for enhanced processing""" |
| try: |
| |
| self.emotion_model = pipeline( |
| "image-classification", |
| model="microsoft/DialoGPT-medium", |
| device=0 if torch.cuda.is_available() else -1 |
| ) |
| |
| |
| self.scene_model = pipeline( |
| "image-classification", |
| model="microsoft/resnet-50", |
| device=0 if torch.cuda.is_available() else -1 |
| ) |
| |
| |
| self.face_quality_model = pipeline( |
| "image-classification", |
| model="microsoft/beit-base-patch16-224", |
| device=0 if torch.cuda.is_available() else -1 |
| ) |
| |
| print("✅ AI models loaded successfully") |
| |
| except Exception as e: |
| print(f"⚠️ Some AI models failed to load: {e}") |
| |
| self.emotion_model = None |
| self.scene_model = None |
| self.face_quality_model = None |
|
|
| class HighQualityImageProcessor: |
| """Advanced image processing with AI enhancement""" |
| |
| def __init__(self): |
| self.core = AIEnhancedCore() |
| |
| def enhance_image_quality(self, image_path: str, output_path: str = None) -> str: |
| """Apply high-quality image enhancement""" |
| if output_path is None: |
| output_path = image_path |
| |
| |
| img = Image.open(image_path) |
| |
| |
| img = self._reduce_noise_advanced(img) |
| img = self._enhance_colors(img) |
| img = self._improve_sharpness(img) |
| img = self._optimize_dynamic_range(img) |
| img = self._apply_super_resolution(img) |
| |
| |
| img.save(output_path, quality=100, optimize=False) |
| |
| return output_path |
| |
| def _apply_super_resolution(self, img: Image.Image) -> Image.Image: |
| """Apply AI super resolution for maximum quality""" |
| try: |
| |
| width, height = img.size |
| |
| |
| target_width = max(1920, width * 2) |
| target_height = max(1080, height * 2) |
| |
| |
| img = img.resize((target_width, target_height), Image.Resampling.LANCZOS) |
| |
| |
| img = img.filter(ImageFilter.UnsharpMask(radius=1, percent=200, threshold=2)) |
| |
| except Exception as e: |
| print(f"Super resolution failed: {e}") |
| return img |
| |
| def _reduce_noise_advanced(self, img: Image.Image) -> Image.Image: |
| """Quick noise reduction for faster processing""" |
| |
| img_array = np.array(img) |
| |
| |
| img_array = cv2.bilateralFilter(img_array, 5, 50, 50) |
| |
| return Image.fromarray(img_array) |
| |
| def _enhance_colors(self, img: Image.Image) -> Image.Image: |
| """AI-powered color enhancement for maximum quality""" |
| |
| enhancer = ImageEnhance.Color(img) |
| img = enhancer.enhance(1.3) |
| |
| |
| enhancer = ImageEnhance.Contrast(img) |
| img = enhancer.enhance(1.2) |
| |
| |
| enhancer = ImageEnhance.Brightness(img) |
| img = enhancer.enhance(1.1) |
| |
| |
| enhancer = ImageEnhance.Color(img) |
| img = enhancer.enhance(1.25) |
| |
| |
| enhancer = ImageEnhance.Sharpness(img) |
| img = enhancer.enhance(1.1) |
| |
| return img |
| |
| def _improve_sharpness(self, img: Image.Image) -> Image.Image: |
| """Advanced sharpness improvement""" |
| |
| img = img.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3)) |
| |
| |
| img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) |
| |
| return img |
| |
| def _optimize_dynamic_range(self, img: Image.Image) -> Image.Image: |
| """Optimize dynamic range for better visibility""" |
| |
| img_array = np.array(img) |
| lab = cv2.cvtColor(img_array, cv2.COLOR_RGB2LAB) |
| |
| |
| clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) |
| lab[:,:,0] = clahe.apply(lab[:,:,0]) |
| |
| |
| img_array = cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) |
| |
| return Image.fromarray(img_array) |
|
|
| class AIComicStyler: |
| """Advanced AI-powered comic styling""" |
| |
| def __init__(self): |
| self.core = AIEnhancedCore() |
| self.preserve_colors = True |
| |
| def apply_comic_style(self, image_path: str, style_type: str = "modern") -> str: |
| """Apply high-quality comic styling""" |
| img = cv2.imread(image_path) |
| |
| if style_type == "modern": |
| return self._apply_modern_style(img, image_path) |
| elif style_type == "classic": |
| return self._apply_classic_style(img, image_path) |
| elif style_type == "manga": |
| return self._apply_manga_style(img, image_path) |
| else: |
| return self._apply_modern_style(img, image_path) |
| |
| def _apply_modern_style(self, img: np.ndarray, image_path: str) -> str: |
| """Modern comic style with AI enhancement""" |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| |
| |
| edges1 = cv2.Canny(gray, 50, 150) |
| edges2 = cv2.Canny(gray, 100, 200) |
| edges = cv2.bitwise_or(edges1, edges2) |
| |
| |
| |
| data = img.reshape((-1, 3)) |
| data = np.float32(data) |
| |
| |
| if self.preserve_colors: |
| |
| optimal_k = min(32, self._determine_optimal_colors(img) * 2) |
| else: |
| optimal_k = self._determine_optimal_colors(img) |
| |
| criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0) |
| _, labels, centers = cv2.kmeans(data, optimal_k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) |
| |
| centers = np.uint8(centers) |
| quantized = centers[labels.flatten()] |
| quantized = quantized.reshape(img.shape) |
| |
| |
| if self.preserve_colors: |
| quantized = cv2.addWeighted(img, 0.3, quantized, 0.7, 0) |
| |
| |
| |
| smoothed = cv2.bilateralFilter(quantized, 9, 75, 75) |
| |
| |
| |
| edges_inv = cv2.bitwise_not(edges) |
| |
| |
| comic = cv2.bitwise_and(smoothed, smoothed, mask=edges_inv) |
| |
| |
| comic = self._add_texture(comic) |
| |
| |
| comic = self._final_enhancement(comic) |
| |
| |
| if self.preserve_colors: |
| |
| final = cv2.addWeighted(img, 0.4, comic, 0.6, 0) |
| else: |
| final = comic |
| |
| |
| cv2.imwrite(image_path, final, [cv2.IMWRITE_JPEG_QUALITY, 100, cv2.IMWRITE_PNG_COMPRESSION, 0]) |
| |
| return image_path |
| |
| def _determine_optimal_colors(self, img: np.ndarray) -> int: |
| """AI-powered optimal color count determination""" |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| |
| |
| hist = cv2.calcHist([gray], [0], None, [256], [0, 256]) |
| hist = hist / hist.sum() |
| entropy = -np.sum(hist * np.log2(hist + 1e-10)) |
| |
| |
| if entropy < 4.0: |
| return 8 |
| elif entropy < 6.0: |
| return 16 |
| elif entropy < 7.5: |
| return 24 |
| else: |
| return 32 |
| |
| def _add_texture(self, img: np.ndarray) -> np.ndarray: |
| """Add subtle texture for comic effect""" |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| |
| |
| height, width = gray.shape |
| pattern = np.zeros((height, width), dtype=np.uint8) |
| |
| for y in range(0, height, 4): |
| for x in range(0, width, 4): |
| if y < height and x < width: |
| intensity = gray[y, x] |
| if intensity < 128: |
| pattern[y:y+2, x:x+2] = 255 |
| |
| |
| texture = cv2.cvtColor(pattern, cv2.COLOR_GRAY2BGR) |
| result = cv2.addWeighted(img, 0.9, texture, 0.1, 0) |
| |
| return result |
| |
| def _final_enhancement(self, img: np.ndarray) -> np.ndarray: |
| """Final enhancement for comic style""" |
| |
| lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) |
| clahe = cv2.createCLAHE(clipLimit=1.5, tileGridSize=(8,8)) |
| lab[:,:,0] = clahe.apply(lab[:,:,0]) |
| img = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) |
| |
| |
| hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) |
| hsv[:,:,1] = cv2.multiply(hsv[:,:,1], 1.2) |
| img = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) |
| |
| return img |
| |
| def _apply_classic_style(self, img: np.ndarray, image_path: str) -> str: |
| """Classic comic book style""" |
| |
| return self._apply_modern_style(img, image_path) |
| |
| def _apply_manga_style(self, img: np.ndarray, image_path: str) -> str: |
| """Manga-style comic effect""" |
| |
| return self._apply_modern_style(img, image_path) |
|
|
| class AIFaceDetector: |
| """Advanced AI-powered face detection and analysis""" |
| |
| def __init__(self): |
| self.core = AIEnhancedCore() |
| self.face_mesh = self.core.face_mesh |
| |
| def detect_faces(self, image_path: str) -> List[Dict]: |
| """Basic face detection (fallback method)""" |
| img = cv2.imread(image_path) |
| if img is None: |
| return [] |
| |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') |
| faces_cv = face_cascade.detectMultiScale(gray, 1.1, 4) |
| |
| faces = [] |
| for (x, y, w, h) in faces_cv: |
| face_data = { |
| 'face_box': {'x': x, 'y': y, 'width': w, 'height': h}, |
| 'lip_position': (x + w//2, y + h//2), |
| 'eye_positions': [(x + w//3, y + h//3), (x + 2*w//3, y + h//3)], |
| 'face_angle': 0, |
| 'confidence': 0.8 |
| } |
| faces.append(face_data) |
| |
| return faces |
| |
| def get_lip_position(self, image_path: str, face_data: Dict) -> Tuple[int, int]: |
| """Get lip position from face data""" |
| if 'lip_position' in face_data: |
| return face_data['lip_position'] |
| else: |
| |
| face_box = face_data.get('face_box', {}) |
| x = face_box.get('x', 0) + face_box.get('width', 0) // 2 |
| y = face_box.get('y', 0) + face_box.get('height', 0) // 2 |
| return (x, y) |
| |
| def detect_faces_advanced(self, image_path: str) -> List[Dict]: |
| """Advanced face detection with AI analysis""" |
| img = cv2.imread(image_path) |
| if img is None: |
| return [] |
| |
| rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) |
| results = self.face_mesh.process(rgb_img) |
| |
| faces = [] |
| if results.multi_face_landmarks: |
| for face_landmarks in results.multi_face_landmarks: |
| face_data = self._analyze_face(face_landmarks, img.shape) |
| faces.append(face_data) |
| |
| return faces |
| |
| def _analyze_face(self, landmarks, img_shape) -> Dict: |
| """Analyze individual face for comprehensive data""" |
| height, width = img_shape[:2] |
| |
| |
| points = [] |
| for landmark in landmarks.landmark: |
| x = int(landmark.x * width) |
| y = int(landmark.y * height) |
| points.append((x, y)) |
| |
| |
| x_coords = [p[0] for p in points] |
| y_coords = [p[1] for p in points] |
| |
| face_box = { |
| 'x': min(x_coords), |
| 'y': min(y_coords), |
| 'width': max(x_coords) - min(x_coords), |
| 'height': max(y_coords) - min(y_coords) |
| } |
| |
| |
| upper_lip = points[13] |
| lower_lip = points[14] |
| lip_center = ( |
| int((upper_lip[0] + lower_lip[0]) / 2), |
| int((upper_lip[1] + lower_lip[1]) / 2) |
| ) |
| |
| |
| left_eye = points[33] |
| right_eye = points[263] |
| |
| |
| eye_angle = np.arctan2(right_eye[1] - left_eye[1], right_eye[0] - left_eye[0]) |
| |
| return { |
| 'face_box': face_box, |
| 'lip_position': lip_center, |
| 'eye_positions': [left_eye, right_eye], |
| 'face_angle': eye_angle, |
| 'confidence': 0.95 |
| } |
|
|
| class AILayoutOptimizer: |
| """AI-powered layout optimization""" |
| |
| def __init__(self): |
| self.core = AIEnhancedCore() |
| |
| def optimize_layout(self, images: List[str], target_layout: str = "2x2") -> List[Dict]: |
| """Optimize layout based on image content analysis""" |
| analyzed_images = [] |
| |
| for img_path in images: |
| analysis = self._analyze_image_content(img_path) |
| analyzed_images.append(analysis) |
| |
| |
| optimal_layout = self._determine_optimal_layout(analyzed_images, target_layout) |
| |
| return optimal_layout |
| |
| def _analyze_image_content(self, image_path: str) -> Dict: |
| """Analyze image content for layout optimization""" |
| img = cv2.imread(image_path) |
| if img is None: |
| return {'complexity': 'low', 'faces': 0, 'action': 'low'} |
| |
| |
| faces = [] |
| try: |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') |
| face_rects = face_cascade.detectMultiScale(gray, 1.1, 4) |
| faces = [(x, y, w, h) for (x, y, w, h) in face_rects] |
| except: |
| faces = [] |
| |
| |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
| edges = cv2.Canny(gray, 50, 150) |
| edge_density = np.sum(edges > 0) / (edges.shape[0] * edges.shape[1]) |
| |
| |
| if edge_density < 0.05: |
| complexity = 'low' |
| elif edge_density < 0.15: |
| complexity = 'medium' |
| else: |
| complexity = 'high' |
| |
| return { |
| 'complexity': complexity, |
| 'faces': len(faces), |
| 'action': 'high' if len(faces) > 1 else 'low', |
| 'edge_density': edge_density |
| } |
| |
| def _determine_optimal_layout(self, analyzed_images: List[Dict], target_layout: str) -> List[Dict]: |
| """Determine optimal panel layout""" |
| if target_layout == "2x2": |
| return self._create_2x2_layout(analyzed_images) |
| else: |
| return self._create_adaptive_layout(analyzed_images) |
| |
| def _create_2x2_layout(self, analyzed_images: List[Dict]) -> List[Dict]: |
| """Create optimized 2x2 layout""" |
| layout = [] |
| |
| for i, analysis in enumerate(analyzed_images[:4]): |
| panel = { |
| 'index': i, |
| 'type': '6', |
| 'span': (2, 2), |
| 'priority': 'high' if analysis['faces'] > 0 else 'medium', |
| 'content_analysis': analysis |
| } |
| layout.append(panel) |
| |
| return layout |
| |
| def _create_adaptive_layout(self, analyzed_images: List[Dict]) -> List[Dict]: |
| """Create adaptive layout based on content""" |
| |
| return self._create_2x2_layout(analyzed_images) |
|
|
| |
| image_processor = HighQualityImageProcessor() |
| comic_styler = AIComicStyler() |
| face_detector = AIFaceDetector() |
| layout_optimizer = AILayoutOptimizer() |