| | """ |
| | 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() |