Image Segmentation
medical
biology
vascx / vascx_models /utils.py
Jose
new inference utilities
1b052a1
from pathlib import Path
from typing import Dict, Optional, Tuple
import numpy as np
from PIL import Image, ImageDraw
def create_fundus_overlay(
rgb_path: str,
av_path: Optional[str] = None,
disc_path: Optional[str] = None,
fovea_location: Optional[Tuple[int, int]] = None,
output_path: Optional[str] = None,
) -> np.ndarray:
"""
Create a visualization of a fundus image with overlaid segmentations and markers.
Args:
rgb_path: Path to the RGB fundus image
av_path: Optional path to artery-vein segmentation (1=artery, 2=vein, 3=intersection)
disc_path: Optional path to binary disc segmentation
fovea_location: Optional (x,y) tuple indicating the location of the fovea
output_path: Optional path to save the visualization image
Returns:
Numpy array containing the visualization image
"""
print(rgb_path, av_path, disc_path, fovea_location, output_path)
# Load RGB image
rgb_img = np.array(Image.open(rgb_path))
# Create output image starting with the RGB image
output_img = rgb_img.copy()
# Load and overlay AV segmentation if provided
if av_path:
av_mask = np.array(Image.open(av_path))
# Create masks for arteries (1), veins (2) and intersections (3)
artery_mask = av_mask == 1
vein_mask = av_mask == 2
intersection_mask = av_mask == 3
# Combine artery and intersection for visualization
artery_combined = np.logical_or(artery_mask, intersection_mask)
vein_combined = np.logical_or(vein_mask, intersection_mask)
# Apply colors: red for arteries, blue for veins
# Red channel - increase for arteries
output_img[artery_combined, 0] = 255
output_img[artery_combined, 1] = 0
output_img[artery_combined, 2] = 0
# Blue channel - increase for veins
output_img[vein_combined, 0] = 0
output_img[vein_combined, 1] = 0
output_img[vein_combined, 2] = 255
# Load and overlay optic disc segmentation if provided
if disc_path:
disc_mask = np.array(Image.open(disc_path)) > 0
# Apply white color for disc
output_img[disc_mask, :] = [255, 255, 255] # White
# Convert to PIL image for drawing the fovea marker
pil_img = Image.fromarray(output_img)
# Add fovea marker if provided
if fovea_location:
draw = ImageDraw.Draw(pil_img)
x, y = fovea_location
marker_size = (
min(pil_img.width, pil_img.height) // 50
) # Scale marker with image
# Draw yellow X at fovea location
draw.line(
[(x - marker_size, y - marker_size), (x + marker_size, y + marker_size)],
fill=(255, 255, 0),
width=2,
)
draw.line(
[(x - marker_size, y + marker_size), (x + marker_size, y - marker_size)],
fill=(255, 255, 0),
width=2,
)
# Convert back to numpy array
output_img = np.array(pil_img)
# Save output if path provided
if output_path:
Image.fromarray(output_img).save(output_path)
return output_img
def batch_create_overlays(
rgb_dir: Path,
output_dir: Path,
av_dir: Optional[Path] = None,
disc_dir: Optional[Path] = None,
fovea_data: Optional[Dict[str, Tuple[int, int]]] = None,
) -> None:
"""
Create visualization overlays for a batch of images.
Args:
rgb_dir: Directory containing RGB fundus images
output_dir: Directory to save visualization images
av_dir: Optional directory containing AV segmentations
disc_dir: Optional directory containing disc segmentations
fovea_data: Optional dictionary mapping image IDs to fovea coordinates
Returns:
List of paths to created visualization images
"""
# Create output directory if it doesn't exist
output_dir.mkdir(exist_ok=True, parents=True)
# Get all RGB images
rgb_files = list(rgb_dir.glob("*.png"))
if not rgb_files:
return []
# Process each image
for rgb_file in rgb_files:
image_id = rgb_file.stem
# Check for corresponding AV segmentation
av_file = None
if av_dir:
av_file_path = av_dir / f"{image_id}.png"
if av_file_path.exists():
av_file = str(av_file_path)
# Check for corresponding disc segmentation
disc_file = None
if disc_dir:
disc_file_path = disc_dir / f"{image_id}.png"
if disc_file_path.exists():
disc_file = str(disc_file_path)
# Get fovea location if available
fovea_location = None
if fovea_data and image_id in fovea_data:
fovea_location = fovea_data[image_id]
# Create output path
output_file = output_dir / f"{image_id}.png"
# Create and save overlay
create_fundus_overlay(
rgb_path=str(rgb_file),
av_path=av_file,
disc_path=disc_file,
fovea_location=fovea_location,
output_path=str(output_file),
)