|
|
""" |
|
|
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) |
|
|
|
|
|
|
|
|
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): |
|
|
hist_orig = cv2.calcHist([orig_array[:, :, channel]], [0], None, [256], [0, 256]) |
|
|
hist_mosaic = cv2.calcHist([mosaic_array[:, :, channel]], [0], None, [256], [0, 256]) |
|
|
|
|
|
|
|
|
hist_orig = hist_orig.flatten() / np.sum(hist_orig) |
|
|
hist_mosaic = hist_mosaic.flatten() / np.sum(hist_mosaic) |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
orig_gray = np.array(original.convert('L')) |
|
|
mosaic_gray = np.array(mosaic_resized.convert('L')) |
|
|
|
|
|
|
|
|
orig_edges = cv2.Canny(orig_gray, 50, 150) |
|
|
mosaic_edges = cv2.Canny(mosaic_gray, 50, 150) |
|
|
|
|
|
|
|
|
intersection = np.logical_and(orig_edges, mosaic_edges).sum() |
|
|
union = np.logical_or(orig_edges, mosaic_edges).sum() |
|
|
|
|
|
if union == 0: |
|
|
return 1.0 |
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
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}") |
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
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 = 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 |