Spaces:
Sleeping
Sleeping
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| def preprocess_image(image, target_width=420, target_height=130): | |
| """ | |
| Preprocess input image to match training data format: | |
| - Convert to black background with white foreground | |
| - Resize to target dimensions | |
| - Enhance contrast for better detection | |
| Args: | |
| image: Input image (numpy array or PIL Image) | |
| target_width: Width to resize to (default: 420) | |
| target_height: Height to resize to (default: 130) | |
| Returns: | |
| Preprocessed image as numpy array | |
| """ | |
| # Convert PIL Image to numpy array if needed | |
| if isinstance(image, Image.Image): | |
| image_np = np.array(image) | |
| else: | |
| image_np = image.copy() | |
| # Convert to grayscale if colored | |
| if len(image_np.shape) == 3 and image_np.shape[2] == 3: | |
| gray_img = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY) | |
| else: | |
| gray_img = image_np | |
| # Make sure image is uint8 for cv2 operations | |
| if gray_img.dtype != np.uint8: | |
| gray_img = (gray_img * 255).astype(np.uint8) | |
| # Determine foreground/background colors | |
| mean_value = np.mean(gray_img) | |
| is_dark_background = mean_value < 128 | |
| # Invert if needed to get dark background/light foreground | |
| if not is_dark_background: | |
| gray_img = 255 - gray_img | |
| # Apply adaptive thresholding to enhance contrast | |
| # This helps with handwritten content with varying pressure/intensity | |
| binary_img = cv2.adaptiveThreshold( | |
| gray_img, | |
| 255, | |
| cv2.ADAPTIVE_THRESH_GAUSSIAN_C, | |
| cv2.THRESH_BINARY_INV, | |
| 11, # Block size | |
| 2 # Constant subtracted from mean | |
| ) | |
| # Resize to target dimensions | |
| # Use INTER_AREA for shrinking, INTER_CUBIC for enlarging | |
| current_height, current_width = binary_img.shape | |
| if current_width > target_width or current_height > target_height: | |
| interpolation = cv2.INTER_AREA | |
| else: | |
| interpolation = cv2.INTER_CUBIC | |
| # Calculate scaling ratio to maintain aspect ratio | |
| width_ratio = target_width / current_width | |
| height_ratio = target_height / current_height | |
| scaling_ratio = min(width_ratio, height_ratio) | |
| # Calculate new dimensions | |
| new_width = int(current_width * scaling_ratio) | |
| new_height = int(current_height * scaling_ratio) | |
| # Resize while maintaining aspect ratio | |
| resized_img = cv2.resize(binary_img, (new_width, new_height), interpolation=interpolation) | |
| # Create black canvas of target size | |
| final_img = np.zeros((target_height, target_width), dtype=np.uint8) | |
| # Calculate position to center the resized image | |
| x_offset = (target_width - new_width) // 2 | |
| y_offset = (target_height - new_height) // 2 | |
| # Place the resized image on the canvas | |
| final_img[y_offset:y_offset+new_height, x_offset:x_offset+new_width] = resized_img | |
| # Invert to get white foreground on black background | |
| final_img = 255 - final_img | |
| # Apply additional contrast enhancement if needed | |
| # This can help with faint or inconsistent handwriting | |
| clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) | |
| enhanced_img = clahe.apply(final_img) | |
| # Optional: Apply slight Gaussian blur to reduce noise | |
| # Only apply if the image seems noisy | |
| enhanced_img = cv2.GaussianBlur(enhanced_img, (3, 3), 0) | |
| return enhanced_img | |