image-eval / app.py
VOIDER's picture
Upload 11 files
4082624 verified
"""
Main application file for the Image Evaluator tool.
This module integrates all components and provides a Gradio interface.
"""
import os
import gradio as gr
import numpy as np
import pandas as pd
import torch
import glob
from PIL import Image
import json
import tempfile
import shutil
from datetime import datetime
# Import custom modules
from modules.metadata_extractor import MetadataExtractor
from modules.technical_metrics import TechnicalMetrics
from modules.aesthetic_metrics import AestheticMetrics
from modules.aggregator import ResultsAggregator
from modules.visualizer import Visualizer
class ImageEvaluator:
"""Main class for the Image Evaluator application."""
def __init__(self):
"""Initialize the Image Evaluator."""
self.results_dir = os.path.join(os.getcwd(), "results")
os.makedirs(self.results_dir, exist_ok=True)
# Initialize components
self.metadata_extractor = MetadataExtractor()
self.technical_metrics = TechnicalMetrics()
self.aesthetic_metrics = AestheticMetrics()
self.aggregator = ResultsAggregator()
self.visualizer = Visualizer(self.results_dir)
# Storage for results
self.evaluation_results = {}
self.metadata_cache = {}
self.current_comparison = None
def process_images(self, image_files, progress=None):
"""
Process a list of image files and extract metadata.
Args:
image_files: list of image file paths
progress: optional gradio Progress object
Returns:
tuple: (metadata_by_model, metadata_by_prompt)
"""
metadata_list = []
total_files = len(image_files)
for i, img_path in enumerate(image_files):
# Safe progress update without accessing internal attributes
if progress is not None:
try:
progress((i + 1) / total_files, f"Processing image {i+1}/{total_files}")
except Exception as e:
print(f"Progress update error (non-critical): {e}")
# Extract metadata
metadata = self.metadata_extractor.extract_metadata(img_path)
metadata_list.append((img_path, metadata))
# Cache metadata
self.metadata_cache[img_path] = metadata
# Group by model and prompt
metadata_by_model = self.metadata_extractor.group_images_by_model(metadata_list)
metadata_by_prompt = self.metadata_extractor.group_images_by_prompt(metadata_list)
return metadata_by_model, metadata_by_prompt
def evaluate_images(self, image_files, progress=None):
"""
Evaluate a list of image files using all metrics.
Args:
image_files: list of image file paths
progress: optional gradio Progress object
Returns:
dict: evaluation results by image path
"""
results = {}
total_files = len(image_files)
for i, img_path in enumerate(image_files):
# Safe progress update without accessing internal attributes
if progress is not None:
try:
progress((i + 1) / total_files, f"Evaluating image {i+1}/{total_files}")
except Exception as e:
print(f"Progress update error (non-critical): {e}")
# Get metadata if available
metadata = self.metadata_cache.get(img_path, {})
prompt = metadata.get('prompt', '')
# Calculate technical metrics
tech_metrics = self.technical_metrics.calculate_all_metrics(img_path)
# Calculate aesthetic metrics
aesthetic_metrics = self.aesthetic_metrics.calculate_all_metrics(img_path, prompt)
# Combine results
combined_metrics = {**tech_metrics, **aesthetic_metrics}
# Store results
results[img_path] = combined_metrics
return results
def compare_models(self, evaluation_results, metadata_by_model):
"""
Compare different models based on evaluation results.
Args:
evaluation_results: dictionary with image paths as keys and metrics as values
metadata_by_model: dictionary with model names as keys and lists of image paths as values
Returns:
tuple: (comparison_df, visualizations)
"""
# Group results by model
results_by_model = {}
for model, image_paths in metadata_by_model.items():
model_results = [evaluation_results[img] for img in image_paths if img in evaluation_results]
results_by_model[model] = model_results
# Compare models
comparison = self.aggregator.compare_models(results_by_model)
# Create comparison dataframe
comparison_df = self.aggregator.create_comparison_dataframe(comparison)
# Store current comparison
self.current_comparison = comparison_df
# Create visualizations
visualizations = {}
# Create heatmap
heatmap_path = self.visualizer.plot_heatmap(comparison_df)
visualizations['Model Comparison Heatmap'] = heatmap_path
# Create radar chart for key metrics
key_metrics = ['aesthetic_score', 'sharpness', 'noise', 'contrast', 'color_harmony', 'prompt_similarity']
available_metrics = [m for m in key_metrics if m in comparison_df.columns]
if available_metrics:
radar_path = self.visualizer.plot_radar_chart(comparison_df, available_metrics)
visualizations['Model Comparison Radar Chart'] = radar_path
# Create bar charts for important metrics
for metric in ['overall_score', 'aesthetic_score', 'prompt_similarity']:
if metric in comparison_df.columns:
bar_path = self.visualizer.plot_metric_comparison(comparison_df, metric)
visualizations[f'{metric} Comparison'] = bar_path
return comparison_df, visualizations
def export_results(self, format='csv'):
"""
Export current comparison results.
Args:
format: export format ('csv', 'excel', or 'html')
Returns:
str: path to exported file
"""
if self.current_comparison is not None:
return self.visualizer.export_comparison_table(self.current_comparison, format)
return None
def generate_report(self, comparison_df, visualizations):
"""
Generate a comprehensive HTML report.
Args:
comparison_df: pandas DataFrame with comparison data
visualizations: dictionary of visualization paths
Returns:
str: path to HTML report
"""
metrics_list = comparison_df.columns.tolist()
return self.visualizer.generate_html_report(comparison_df, visualizations, metrics_list)
# Create Gradio interface
def create_interface():
"""Create and configure the Gradio interface."""
# Initialize evaluator
evaluator = ImageEvaluator()
# Track state
state = {
'uploaded_images': [],
'metadata_by_model': {},
'metadata_by_prompt': {},
'evaluation_results': {},
'comparison_df': None,
'visualizations': {},
'report_path': None
}
def upload_images(files):
"""Handle image upload and processing."""
# Reset state
state['uploaded_images'] = []
state['metadata_by_model'] = {}
state['metadata_by_prompt'] = {}
state['evaluation_results'] = {}
state['comparison_df'] = None
state['visualizations'] = {}
state['report_path'] = None
# Process uploaded files
image_paths = [f.name for f in files]
state['uploaded_images'] = image_paths
# Extract metadata and group images
# Use a simple progress message instead of Gradio Progress object
print("Extracting metadata...")
metadata_by_model, metadata_by_prompt = evaluator.process_images(image_paths)
state['metadata_by_model'] = metadata_by_model
state['metadata_by_prompt'] = metadata_by_prompt
# Create model summary
model_summary = []
for model, images in metadata_by_model.items():
model_summary.append(f"- {model}: {len(images)} images")
# Create prompt summary
prompt_summary = []
for prompt, images in metadata_by_prompt.items():
prompt_summary.append(f"- {prompt}: {len(images)} images")
return (
f"Processed {len(image_paths)} images.\n\n"
f"Found {len(metadata_by_model)} models:\n" + "\n".join(model_summary) + "\n\n"
f"Found {len(metadata_by_prompt)} unique prompts."
)
def evaluate_images():
"""Evaluate all uploaded images."""
if not state['uploaded_images']:
return "No images uploaded. Please upload images first."
# Evaluate images
# Use a simple progress message instead of Gradio Progress object
print("Evaluating images...")
evaluation_results = evaluator.evaluate_images(state['uploaded_images'])
state['evaluation_results'] = evaluation_results
return f"Evaluated {len(evaluation_results)} images with all metrics."
def compare_models():
"""Compare models based on evaluation results."""
if not state['evaluation_results'] or not state['metadata_by_model']:
return "No evaluation results available. Please evaluate images first.", None, None
# Compare models
comparison_df, visualizations = evaluator.compare_models(
state['evaluation_results'], state['metadata_by_model']
)
state['comparison_df'] = comparison_df
state['visualizations'] = visualizations
# Generate report
report_path = evaluator.generate_report(comparison_df, visualizations)
state['report_path'] = report_path
# Get visualization paths
heatmap_path = visualizations.get('Model Comparison Heatmap')
radar_path = visualizations.get('Model Comparison Radar Chart')
overall_score_path = visualizations.get('overall_score Comparison')
# Convert DataFrame to markdown for display
df_markdown = comparison_df.to_markdown()
return df_markdown, heatmap_path, radar_path
def export_results(format):
"""Export results in the specified format."""
if state['comparison_df'] is None:
return "No comparison results available. Please compare models first."
export_path = evaluator.export_results(format)
if export_path:
return f"Results exported to {export_path}"
else:
return "Failed to export results."
def view_report():
"""View the generated HTML report."""
if state['report_path'] and os.path.exists(state['report_path']):
return state['report_path']
else:
return "No report available. Please compare models first."
# Create interface
with gr.Blocks(title="Image Model Evaluator") as interface:
gr.Markdown("# Image Model Evaluator")
gr.Markdown("Upload images generated by different AI models to compare their quality and performance.")
with gr.Tab("Upload & Process"):
with gr.Row():
with gr.Column():
upload_input = gr.File(
label="Upload Images (PNG format)",
file_count="multiple",
type="filepath" # Changed from 'file' to 'filepath'
)
upload_button = gr.Button("Process Uploaded Images")
with gr.Column():
upload_output = gr.Textbox(
label="Processing Results",
lines=10,
interactive=False
)
evaluate_button = gr.Button("Evaluate Images")
evaluate_output = gr.Textbox(
label="Evaluation Status",
lines=2,
interactive=False
)
with gr.Tab("Compare Models"):
compare_button = gr.Button("Compare Models")
with gr.Row():
comparison_output = gr.Markdown(
label="Comparison Results"
)
with gr.Row():
with gr.Column():
heatmap_output = gr.Image(
label="Model Comparison Heatmap",
interactive=False
)
with gr.Column():
radar_output = gr.Image(
label="Model Comparison Radar Chart",
interactive=False
)
with gr.Tab("Export & Report"):
with gr.Row():
with gr.Column():
export_format = gr.Radio(
label="Export Format",
choices=["csv", "excel", "html"],
value="csv"
)
export_button = gr.Button("Export Results")
export_output = gr.Textbox(
label="Export Status",
lines=2,
interactive=False
)
with gr.Column():
report_button = gr.Button("View Full Report")
report_output = gr.HTML(
label="Full Report"
)
# Set up event handlers
upload_button.click(
upload_images,
inputs=[upload_input],
outputs=[upload_output]
)
evaluate_button.click(
evaluate_images,
inputs=[],
outputs=[evaluate_output]
)
compare_button.click(
compare_models,
inputs=[],
outputs=[comparison_output, heatmap_output, radar_output]
)
export_button.click(
export_results,
inputs=[export_format],
outputs=[export_output]
)
report_button.click(
view_report,
inputs=[],
outputs=[report_output]
)
return interface
# Launch the application
if __name__ == "__main__":
interface = create_interface()
# Remove share=True for HuggingFace Spaces
interface.launch()