MakiAi's picture
Upload 84 files
ad8cacf verified
"""
Image refinement functionality.
"""
import os
import cv2
import numpy as np
from loguru import logger
from .splitter import create_output_directory
def refine_animal_illustrations(input_dir='split_animals', refined_dir='refined_animals'):
"""
Refine the extracted animal illustrations by removing excess whitespace.
Args:
input_dir (str): Directory containing the initially split animal images
refined_dir (str): Directory where refined animal images will be saved
Returns:
list: Paths to the refined animal images
"""
# Create refined output directory
refined_dir = create_output_directory(refined_dir)
refined_paths = []
# Process each file in the input directory
for filename in os.listdir(input_dir):
if not filename.lower().endswith(('.png', '.jpg', '.jpeg')):
continue
file_path = os.path.join(input_dir, filename)
try:
# Read image
img = cv2.imread(file_path)
if img is None:
logger.warning(f"Could not read image: {file_path}")
continue
# Process image
refined_img = remove_excess_whitespace(img)
# Save refined image
refined_path = os.path.join(refined_dir, filename)
cv2.imwrite(refined_path, refined_img)
refined_paths.append(refined_path)
logger.info(f"Refined: {refined_path}")
except Exception as e:
logger.error(f"Error processing {file_path}: {str(e)}")
continue
logger.info(f"Refinement complete. Images saved to {refined_dir}")
return refined_paths
def remove_excess_whitespace(img, padding=10):
"""
Remove excess whitespace around the main content of an image.
Args:
img (numpy.ndarray): Input image
padding (int): Padding to add around content
Returns:
numpy.ndarray: Cropped image
"""
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply threshold to separate content from background
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)
# Find contours
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return img
# Find largest contour (assumed to be the main content)
largest_contour = max(contours, key=cv2.contourArea)
# Get bounding rectangle
x, y, w, h = cv2.boundingRect(largest_contour)
# Add padding
x = max(0, x - padding)
y = max(0, y - padding)
w = min(img.shape[1] - x, w + 2 * padding)
h = min(img.shape[0] - y, h + 2 * padding)
# Crop image
return img[y:y+h, x:x+w]
def calculate_content_bounds(gray_img, threshold=240):
"""
Calculate content boundaries in grayscale image.
Args:
gray_img (numpy.ndarray): Grayscale image
threshold (int): Brightness threshold
Returns:
tuple: (min_x, min_y, max_x, max_y)
"""
# Create binary mask
_, mask = cv2.threshold(gray_img, threshold, 255, cv2.THRESH_BINARY_INV)
# Find non-zero points
points = cv2.findNonZero(mask)
if points is None:
return None
# Calculate bounds
x, y, w, h = cv2.boundingRect(points)
return (x, y, x + w, y + h)