""" Performance metrics for comparing original and mosaic images """ import numpy as np from PIL import Image from skimage.metrics import structural_similarity as ssim import cv2 def resize_to_match(original, mosaic): """Resize mosaic to match original image dimensions""" return mosaic.resize(original.size, Image.BICUBIC) def calculate_mse(original, mosaic): """ Calculate Mean Squared Error between two images Lower values indicate better similarity (0 = perfect match) """ mosaic_resized = resize_to_match(original, mosaic) orig_array = np.array(original, dtype=np.float32) mosaic_array = np.array(mosaic_resized, dtype=np.float32) mse = np.mean((orig_array - mosaic_array) ** 2) return float(mse) def calculate_ssim(original, mosaic): """ Calculate Structural Similarity Index Range: [-1, 1], higher values indicate better similarity (1 = perfect match) """ mosaic_resized = resize_to_match(original, mosaic) # Convert to grayscale for SSIM calculation orig_gray = np.array(original.convert('L')) mosaic_gray = np.array(mosaic_resized.convert('L')) ssim_value = ssim(orig_gray, mosaic_gray) return float(ssim_value) def calculate_histogram_correlation(original, mosaic): """ Calculate histogram correlation for each RGB channel Range: [-1, 1], higher values indicate better similarity """ mosaic_resized = resize_to_match(original, mosaic) orig_array = np.array(original) mosaic_array = np.array(mosaic_resized) correlations = [] for channel in range(3): # RGB channels hist_orig = cv2.calcHist([orig_array[:, :, channel]], [0], None, [256], [0, 256]) hist_mosaic = cv2.calcHist([mosaic_array[:, :, channel]], [0], None, [256], [0, 256]) # Normalize histograms hist_orig = hist_orig.flatten() / np.sum(hist_orig) hist_mosaic = hist_mosaic.flatten() / np.sum(hist_mosaic) # Calculate correlation correlation = np.corrcoef(hist_orig, hist_mosaic)[0, 1] correlations.append(correlation) return float(np.mean(correlations)) def calculate_edge_similarity(original, mosaic): """ Calculate edge similarity using Canny edge detection Range: [0, 1], higher values indicate better similarity """ mosaic_resized = resize_to_match(original, mosaic) # Convert to grayscale orig_gray = np.array(original.convert('L')) mosaic_gray = np.array(mosaic_resized.convert('L')) # Apply Canny edge detection orig_edges = cv2.Canny(orig_gray, 50, 150) mosaic_edges = cv2.Canny(mosaic_gray, 50, 150) # Calculate intersection over union (IoU) of edges intersection = np.logical_and(orig_edges, mosaic_edges).sum() union = np.logical_or(orig_edges, mosaic_edges).sum() if union == 0: return 1.0 # No edges in either image edge_similarity = intersection / union return float(edge_similarity) def calculate_all_metrics(original, mosaic): """ Calculate all performance metrics and return as dictionary """ metrics = {} try: metrics['MSE'] = calculate_mse(original, mosaic) metrics['SSIM'] = calculate_ssim(original, mosaic) metrics['Histogram_Correlation'] = calculate_histogram_correlation(original, mosaic) metrics['Edge_Similarity'] = calculate_edge_similarity(original, mosaic) # Calculate overall quality score metrics['Overall_Quality'] = ( metrics['SSIM'] * 0.4 + metrics['Histogram_Correlation'] * 0.3 + metrics['Edge_Similarity'] * 0.3 ) except Exception as e: print(f"Error calculating metrics: {e}") # Return default values if calculation fails metrics = { 'MSE': float('nan'), 'SSIM': float('nan'), 'Histogram_Correlation': float('nan'), 'Edge_Similarity': float('nan'), 'Overall_Quality': float('nan') } return metrics def format_metrics_report(metrics): """ Format metrics into a readable report string """ if not metrics: return "No metrics calculated" report = "Performance Metrics:\n\n" # Core metrics mse = metrics.get('MSE', float('nan')) ssim_val = metrics.get('SSIM', float('nan')) hist_corr = metrics.get('Histogram_Correlation', float('nan')) edge_sim = metrics.get('Edge_Similarity', float('nan')) if not np.isnan(mse): report += f"MSE: {mse:.2f} (lower is better)\n" if not np.isnan(ssim_val): report += f"SSIM: {ssim_val:.4f} (higher is better)\n" if not np.isnan(hist_corr): report += f"Histogram Correlation: {hist_corr:.4f} (higher is better)\n" if not np.isnan(edge_sim): report += f"Edge Similarity: {edge_sim:.4f} (higher is better)\n\n" # Overall quality overall = metrics.get('Overall_Quality', float('nan')) if not np.isnan(overall): report += f"Overall Quality Score: {overall:.4f}\n" if overall > 0.8: report += "Quality: Excellent" elif overall > 0.6: report += "Quality: Good" elif overall > 0.4: report += "Quality: Fair" elif overall > 0.2: report += "Quality: Poor" else: report += "Quality: Very Poor" return report