AbdullahIsaMarkus's picture
Create app.py
c1edb5a verified
import gradio as gr
import numpy as np
import pydicom
from skimage import exposure, measure, filters
from skimage.metrics import structural_similarity as ssim
from skimage.metrics import peak_signal_noise_ratio as psnr
import json
from typing import Dict, List, Tuple
import tempfile
import os
from PIL import Image
class VeterinaryDICOMProcessor:
"""Veterinärmedizinische DICOM-Bildverbesserung und Qualitätsbewertung"""
def __init__(self):
# Spezies-spezifische Parameter für verschiedene Algorithmen
self.species_params = {
"canine": {
"clahe": {"clip_limit": 0.02, "kernel_size": (8, 8)},
"adaptive": {"clip_limit": 0.015, "kernel_size": (6, 6)},
"histogram": {"bins": 256}
},
"feline": {
"clahe": {"clip_limit": 0.015, "kernel_size": (6, 6)},
"adaptive": {"clip_limit": 0.012, "kernel_size": (4, 4)},
"histogram": {"bins": 256}
},
"equine": {
"clahe": {"clip_limit": 0.03, "kernel_size": (12, 12)},
"adaptive": {"clip_limit": 0.025, "kernel_size": (10, 10)},
"histogram": {"bins": 256}
},
"bovine": {
"clahe": {"clip_limit": 0.025, "kernel_size": (10, 10)},
"adaptive": {"clip_limit": 0.02, "kernel_size": (8, 8)},
"histogram": {"bins": 256}
}
}
def load_dicom_or_image(self, file_path: str) -> np.ndarray:
"""Lädt DICOM-Datei oder normale Bilddatei und konvertiert zu Numpy Array"""
try:
# Versuche zuerst DICOM zu laden
if file_path.lower().endswith(('.dcm', '.dicom')):
dicom_data = pydicom.dcmread(file_path)
image = dicom_data.pixel_array.astype(np.float64)
else:
# Lade als normales Bild (für Demo-Zwecke)
pil_image = Image.open(file_path).convert('L') # Graustufen
image = np.array(pil_image, dtype=np.float64)
# Normalisierung für bessere Verarbeitung
if image.max() > image.min():
image = (image - image.min()) / (image.max() - image.min())
return image
except Exception as e:
raise ValueError(f"Fehler beim Laden der Datei: {e}")
def apply_clahe_enhancement(self, image: np.ndarray, species: str) -> np.ndarray:
"""Wendet CLAHE (Contrast Limited Adaptive Histogram Equalization) an"""
params = self.species_params.get(species, self.species_params["canine"])["clahe"]
enhanced = exposure.equalize_adapthist(
image,
kernel_size=params["kernel_size"],
clip_limit=params["clip_limit"],
nbins=256
)
return enhanced
def apply_adaptive_histogram_equalization(self, image: np.ndarray, species: str) -> np.ndarray:
"""Wendet Adaptive Histogram Equalization an (lokale Variante)"""
params = self.species_params.get(species, self.species_params["canine"])["adaptive"]
# Adaptive Histogram Equalization mit kleineren Tiles
enhanced = exposure.equalize_adapthist(
image,
kernel_size=params["kernel_size"],
clip_limit=params["clip_limit"],
nbins=128 # Weniger Bins für adaptives Verfahren
)
return enhanced
def apply_histogram_equalization(self, image: np.ndarray) -> np.ndarray:
"""Standard globale Histogram Equalization"""
return exposure.equalize_hist(image)
def apply_contrast_stretching(self, image: np.ndarray, percentiles: Tuple[float, float] = (2, 98)) -> np.ndarray:
"""Kontrast-Streckung basierend auf Perzentilen"""
p_low, p_high = np.percentile(image, percentiles)
return exposure.rescale_intensity(image, in_range=(p_low, p_high))
def apply_gamma_correction(self, image: np.ndarray, gamma: float = 1.2) -> np.ndarray:
"""Gamma-Korrektur für Helligkeit"""
return exposure.adjust_gamma(image, gamma)
def calculate_quality_metrics(self, original: np.ndarray, enhanced: np.ndarray) -> Dict[str, float]:
"""Berechnet umfassende Bildqualitäts-Metriken"""
# SSIM (Structural Similarity Index)
ssim_score = ssim(original, enhanced, data_range=1.0)
# PSNR (Peak Signal-to-Noise Ratio)
psnr_score = psnr(original, enhanced, data_range=1.0)
# Histogram-basierte Metriken
original_entropy = measure.shannon_entropy(original)
enhanced_entropy = measure.shannon_entropy(enhanced)
# Kontrast-Metriken (RMS Kontrast)
original_contrast = np.sqrt(np.mean((original - original.mean()) ** 2))
enhanced_contrast = np.sqrt(np.mean((enhanced - enhanced.mean()) ** 2))
# Edge-basierte Metriken
original_edges = np.mean(filters.sobel(original))
enhanced_edges = np.mean(filters.sobel(enhanced))
# Dynamikbereich
original_dynamic_range = np.max(original) - np.min(original)
enhanced_dynamic_range = np.max(enhanced) - np.min(enhanced)
return {
"ssim": float(ssim_score),
"psnr": float(psnr_score),
"original_entropy": float(original_entropy),
"enhanced_entropy": float(enhanced_entropy),
"entropy_improvement": float(enhanced_entropy - original_entropy),
"original_contrast": float(original_contrast),
"enhanced_contrast": float(enhanced_contrast),
"contrast_improvement": float(enhanced_contrast - original_contrast),
"original_edge_density": float(original_edges),
"enhanced_edge_density": float(enhanced_edges),
"edge_improvement": float(enhanced_edges - original_edges),
"original_dynamic_range": float(original_dynamic_range),
"enhanced_dynamic_range": float(enhanced_dynamic_range),
"dynamic_range_improvement": float(enhanced_dynamic_range - original_dynamic_range)
}
def array_to_image(self, array: np.ndarray) -> str:
"""Konvertiert Numpy Array zu Base64-String für Output"""
# Normalisiere auf 0-255
img_normalized = ((array - array.min()) / (array.max() - array.min()) * 255).astype(np.uint8)
# Konvertiere zu PIL Image
pil_image = Image.fromarray(img_normalized, mode='L')
# Speichere temporär
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
pil_image.save(tmp_file, format='PNG')
return tmp_file.name
def generate_agent_prompt(self, metrics: Dict[str, float], species: str,
body_part: str, enhancement_method: str) -> str:
"""Generiert strukturierten Prompt für KI-Agent zur Qualitätsbewertung"""
prompt = f"""VETERINÄRMEDIZINISCHE BILDQUALITÄTS-ANALYSE
PATIENT-INFORMATION:
===================
• Spezies: {species.upper()}
• Körperregion: {body_part}
• Verbesserungsmethode: {enhancement_method}
BILDQUALITÄTS-METRIKEN:
======================
• SSIM (Strukturelle Ähnlichkeit): {metrics['ssim']:.3f}
→ 1.0 = perfekte Ähnlichkeit, 0.0 = völlig unterschiedlich
→ Bewertung: {'Ausgezeichnet' if metrics['ssim'] > 0.8 else 'Gut' if metrics['ssim'] > 0.6 else 'Verbesserungsbedürftig'}
• PSNR (Signal-Rausch-Verhältnis): {metrics['psnr']:.1f} dB
→ >30dB = gut, >25dB = akzeptabel, <20dB = problematisch
→ Bewertung: {'Gut' if metrics['psnr'] > 30 else 'Akzeptabel' if metrics['psnr'] > 25 else 'Problematisch'}
• Entropie-Verbesserung: {metrics['entropy_improvement']:.3f}
→ Positiv = mehr Bildinformation, Negativ = Informationsverlust
→ Status: {'Information gewonnen' if metrics['entropy_improvement'] > 0 else 'Information verloren'}
• Kontrast-Verbesserung: {metrics['contrast_improvement']:.3f}
→ Positiv = besserer Kontrast, Negativ = Kontrastverlust
→ Status: {'Kontrast verbessert' if metrics['contrast_improvement'] > 0 else 'Kontrast reduziert'}
• Edge-Verbesserung: {metrics['edge_improvement']:.3f}
→ Positiv = schärfere Strukturen, Negativ = Unschärfe
→ Status: {'Schärfer' if metrics['edge_improvement'] > 0 else 'Unschärfer'}
AUFGABEN FÜR KI-AGENT:
=====================
1. Bewerten Sie die Bildqualität für {species}-Diagnostik (Skala 1-10)
2. Ist die Verbesserung für klinische Diagnose ausreichend?
3. Welche anatomischen Strukturen sind bei {species} in {body_part} besser/schlechter sichtbar?
4. Empfehlen Sie weitere Bildverbesserungsschritte oder alternative Methoden?
5. Identifizieren Sie potenzielle Artefakte oder diagnostische Probleme?
6. Geben Sie spezies-spezifische Interpretationshilfen?
ANTWORT-FORMAT:
==============
- Strukturiert und klinisch relevant
- Fokus auf diagnostischen Nutzen
- Spezies-spezifische Besonderheiten berücksichtigen
- Konkrete Handlungsempfehlungen
"""
return prompt
# Globale Processor-Instanz
processor = VeterinaryDICOMProcessor()
def enhance_dicom_image(image_file, species: str, enhancement_method: str, body_part: str = "unbekannt"):
"""
Verbessert veterinärmedizinische DICOM-Bilder mit verschiedenen Algorithmen.
Args:
image_file: DICOM-Datei oder Testbild
species: Tierart (canine, feline, equine, bovine)
enhancement_method: Verbesserungsmethode (clahe, adaptive, histogram, contrast_stretch, gamma)
body_part: Körperregion für spezifische Analyse
Returns:
Verbessertes Bild und detaillierte Qualitätsmetriken
"""
try:
# Lade Originalbild
if image_file is None:
return None, "❌ Kein Bild hochgeladen"
original_image = processor.load_dicom_or_image(image_file)
# Wähle Verbesserungsmethode
if enhancement_method == "clahe":
enhanced_image = processor.apply_clahe_enhancement(original_image, species)
elif enhancement_method == "adaptive":
enhanced_image = processor.apply_adaptive_histogram_equalization(original_image, species)
elif enhancement_method == "histogram":
enhanced_image = processor.apply_histogram_equalization(original_image)
elif enhancement_method == "contrast_stretch":
enhanced_image = processor.apply_contrast_stretching(original_image)
elif enhancement_method == "gamma":
enhanced_image = processor.apply_gamma_correction(original_image)
else:
enhanced_image = processor.apply_clahe_enhancement(original_image, species)
# Berechne Qualitäts-Metriken
metrics = processor.calculate_quality_metrics(original_image, enhanced_image)
# Generiere Agent-Prompt
agent_prompt = processor.generate_agent_prompt(metrics, species, body_part, enhancement_method)
# Konvertiere verbessertes Bild für Output
enhanced_image_path = processor.array_to_image(enhanced_image)
# Erstelle detaillierten Report
report = f"""
🔬 VETERINÄRMEDIZINISCHE BILDANALYSE
=====================================
📊 QUALITÄTS-METRIKEN:
• SSIM: {metrics['ssim']:.3f} ({'✅ Gut' if metrics['ssim'] > 0.7 else '⚠️ Prüfen'})
• PSNR: {metrics['psnr']:.1f} dB ({'✅ Gut' if metrics['psnr'] > 25 else '⚠️ Niedrig'})
• Entropie: {metrics['entropy_improvement']:+.3f} ({'✅ Information gewonnen' if metrics['entropy_improvement'] > 0 else '❌ Information verloren'})
• Kontrast: {metrics['contrast_improvement']:+.3f} ({'✅ Verbessert' if metrics['contrast_improvement'] > 0 else '❌ Reduziert'})
• Edge-Definition: {metrics['edge_improvement']:+.3f} ({'✅ Schärfer' if metrics['edge_improvement'] > 0 else '❌ Unschärfer'})
🐾 SPEZIES-ANALYSE: {species.upper()}
🎯 METHODE: {enhancement_method.upper()}
📍 REGION: {body_part.upper()}
🤖 KI-AGENT PROMPT:
{agent_prompt}
"""
return enhanced_image_path, report
except Exception as e:
return None, f"❌ Fehler bei Bildverbesserung: {str(e)}"
def compare_enhancement_methods(image_file, species: str, body_part: str = "thorax"):
"""
Vergleicht verschiedene Bildverbesserungsmethoden für veterinärmedizinische Analyse.
Args:
image_file: DICOM-Datei oder Testbild
species: Tierart (canine, feline, equine, bovine)
body_part: Körperregion für Analyse
Returns:
Vergleichstabelle aller Methoden mit Qualitätsmetriken
"""
if image_file is None:
return "❌ Kein Bild hochgeladen"
try:
original_image = processor.load_dicom_or_image(image_file)
methods = ["clahe", "adaptive", "histogram", "contrast_stretch", "gamma"]
results = []
for method in methods:
# Wende Methode an
if method == "clahe":
enhanced = processor.apply_clahe_enhancement(original_image, species)
elif method == "adaptive":
enhanced = processor.apply_adaptive_histogram_equalization(original_image, species)
elif method == "histogram":
enhanced = processor.apply_histogram_equalization(original_image)
elif method == "contrast_stretch":
enhanced = processor.apply_contrast_stretching(original_image)
elif method == "gamma":
enhanced = processor.apply_gamma_correction(original_image)
# Berechne Metriken
metrics = processor.calculate_quality_metrics(original_image, enhanced)
results.append({
"Methode": method.upper(),
"SSIM": f"{metrics['ssim']:.3f}",
"PSNR (dB)": f"{metrics['psnr']:.1f}",
"Entropie Δ": f"{metrics['entropy_improvement']:+.3f}",
"Kontrast Δ": f"{metrics['contrast_improvement']:+.3f}",
"Edge Δ": f"{metrics['edge_improvement']:+.3f}",
"Empfehlung": "✅ Gut" if metrics['ssim'] > 0.7 and metrics['psnr'] > 25 else "⚠️ Prüfen"
})
# Erstelle Vergleichstabelle
comparison = f"""
🔬 METHODEN-VERGLEICH: {species.upper()} - {body_part.upper()}
====================================================
"""
for result in results:
comparison += f"""
📊 {result['Methode']}:
SSIM: {result['SSIM']} | PSNR: {result['PSNR (dB)']} | {result['Empfehlung']}
Entropie: {result['Entropie Δ']} | Kontrast: {result['Kontrast Δ']} | Edges: {result['Edge Δ']}
"""
# Beste Methode identifizieren
best_method = max(results, key=lambda x: float(x['SSIM']))
comparison += f"""
🏆 BESTE METHODE: {best_method['Methode']}
→ Höchste SSIM: {best_method['SSIM']}
→ Empfehlung für {species} {body_part}-Diagnostik
💡 VETERINÄR-TIPP:
- CLAHE: Optimal für lokale Kontrastverbesserung
- ADAPTIVE: Weniger Artefakte, sanfter
- HISTOGRAM: Globale Verbesserung, kann übersättigen
- CONTRAST_STRETCH: Konservativ, für kritische Diagnosen
- GAMMA: Helligkeitsanpassung bei unter-/überbelichteten Bildern
"""
return comparison
except Exception as e:
return f"❌ Fehler beim Methodenvergleich: {str(e)}"
# Gradio Interface
with gr.Blocks(title="🐾 Veterinary DICOM Enhancement MCP Server") as demo:
gr.Markdown("""
# 🐾 Veterinärmedizinische DICOM-Bildverbesserung
**MCP Server für KI-Agenten zur automatischen Bildqualitätsbewertung**
🔬 Spezies-spezifische Bildverbesserung mit CLAHE, Adaptive & Histogram Equalization
""")
with gr.Tab("🎯 Einzelne Bildverbesserung"):
with gr.Row():
with gr.Column():
input_image = gr.File(
label="📁 DICOM-Datei oder Testbild hochladen",
file_types=[".dcm", ".dicom", ".png", ".jpg", ".jpeg"]
)
species = gr.Dropdown(
choices=["canine", "feline", "equine", "bovine"],
label="🐾 Tierart",
value="canine"
)
enhancement_method = gr.Dropdown(
choices=["clahe", "adaptive", "histogram", "contrast_stretch", "gamma"],
label="🔧 Verbesserungsmethode",
value="clahe"
)
body_part = gr.Textbox(
label="📍 Körperregion",
value="thorax",
placeholder="z.B. thorax, abdomen, extremität"
)
with gr.Column():
enhanced_output = gr.Image(label="✨ Verbessertes Bild")
metrics_output = gr.Textbox(
label="📊 Qualitätsanalyse & KI-Agent Prompt",
lines=20,
max_lines=30
)
enhance_btn = gr.Button("🚀 Bild verbessern", variant="primary")
enhance_btn.click(
enhance_dicom_image,
inputs=[input_image, species, enhancement_method, body_part],
outputs=[enhanced_output, metrics_output]
)
with gr.Tab("📊 Methoden-Vergleich"):
with gr.Row():
with gr.Column():
compare_input = gr.File(
label="📁 DICOM-Datei oder Testbild hochladen",
file_types=[".dcm", ".dicom", ".png", ".jpg", ".jpeg"]
)
compare_species = gr.Dropdown(
choices=["canine", "feline", "equine", "bovine"],
label="🐾 Tierart",
value="canine"
)
compare_body_part = gr.Textbox(
label="📍 Körperregion",
value="thorax"
)
with gr.Column():
comparison_output = gr.Textbox(
label="📈 Methoden-Vergleich",
lines=25,
max_lines=35
)
compare_btn = gr.Button("📊 Alle Methoden vergleichen", variant="primary")
compare_btn.click(
compare_enhancement_methods,
inputs=[compare_input, compare_species, compare_body_part],
outputs=[comparison_output]
)
if __name__ == "__main__":
# MCP Server starten für Hugging Face
demo.launch(
server_name="0.0.0.0",
server_port=7860, # HF Standard Port
mcp_server=True, # MCP aktivieren
share=False, # Nicht nötig bei HF
show_error=True,
show_api=True
)