ecg-digitization-experiments / code /scripts /continue_synthetic_processing.py
Ubuntu
Add training scripts and notebooks
b69e447
Raw
History Blame Contribute Delete
4.26 kB
#!/usr/bin/env python3
"""Continue processing synthetic images through stage0/stage1.
Skips already processed images. Uses single GPU (runs alongside training)."""
import os
import sys
import cv2
import numpy as np
import torch
from pathlib import Path
from tqdm import tqdm
# Configuration
INPUT_RAW = '/data/ecg-digitization/synthetic_0001/raw'
INPUT_GT = '/data/ecg-digitization/synthetic_0001/gt'
OUTPUT_RAW = '/data/ecg-digitization/synthetic_0001_processed/raw'
OUTPUT_GT = '/data/ecg-digitization/synthetic_0001_processed/gt'
BASELINE_PATH = '/data/ecg-digitization/hengck23'
def main():
# Create output dirs
Path(OUTPUT_RAW).mkdir(parents=True, exist_ok=True)
Path(OUTPUT_GT).mkdir(parents=True, exist_ok=True)
# Find images that need processing
all_images = sorted(Path(INPUT_RAW).glob('*.png'))
processed = set(p.name for p in Path(OUTPUT_RAW).glob('*.png'))
to_process = [p for p in all_images if p.name not in processed]
print(f"Total images: {len(all_images)}")
print(f"Already processed: {len(processed)}")
print(f"To process: {len(to_process)}")
if len(to_process) == 0:
print("All done!")
return
# Setup device - use GPU 0 only (others are for training)
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
device = torch.device('cuda')
# Import baseline modules
sys.path.insert(0, BASELINE_PATH)
from stage0_model import Net as Stage0Net
from stage0_common import image_to_batch, output_to_predict, normalise_by_homography, load_net
from stage1_model import Net as Stage1Net
from stage1_common import output_to_predict as stage1_output_to_predict, rectify_image
# Load models
print("Loading Stage 0...")
stage0_net = Stage0Net(pretrained=False)
stage0_net = load_net(stage0_net, f'{BASELINE_PATH}/weight/stage0-last.checkpoint.pth')
stage0_net.to(device).eval()
print("Loading Stage 1...")
stage1_net = Stage1Net(pretrained=False)
stage1_net = load_net(stage1_net, f'{BASELINE_PATH}/weight/stage1-last.checkpoint.pth')
stage1_net.to(device).eval()
@torch.no_grad()
def process_image(image_rgb):
"""Process through stage0 and stage1."""
# Stage 0
batch = image_to_batch(image_rgb)
with torch.amp.autocast('cuda', dtype=torch.float32):
output = stage0_net(batch)
rotated, keypoint = output_to_predict(image_rgb, batch, output)
normalized, _, _ = normalise_by_homography(rotated, keypoint)
# Stage 1
batch = {'image': torch.from_numpy(np.ascontiguousarray(normalized.transpose(2, 0, 1))).unsqueeze(0)}
with torch.amp.autocast('cuda', dtype=torch.float32):
output = stage1_net(batch)
gridpoint_xy, _ = stage1_output_to_predict(normalized, batch, output)
rectified = rectify_image(normalized, gridpoint_xy)
return rectified
success = 0
failed = 0
for img_path in tqdm(to_process, desc="Processing"):
gt_csv_path = Path(INPUT_GT) / f"{img_path.stem}.csv"
out_img_path = Path(OUTPUT_RAW) / img_path.name
out_gt_path = Path(OUTPUT_GT) / f"{img_path.stem}.csv"
# Load image
image = cv2.imread(str(img_path))
if image is None:
failed += 1
continue
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
try:
# Process through stage0/stage1
rectified = process_image(image_rgb)
# Save processed image
cv2.imwrite(str(out_img_path), cv2.cvtColor(rectified, cv2.COLOR_RGB2BGR))
# Copy GT (no need to transform - it's already in pixel coordinates relative to the final layout)
if gt_csv_path.exists():
import shutil
shutil.copy(gt_csv_path, out_gt_path)
success += 1
except Exception as e:
failed += 1
if failed <= 5:
print(f" Failed {img_path.name}: {e}")
print(f"\nDone: {success} success, {failed} failed")
print(f"Total processed: {len(processed) + success}")
if __name__ == '__main__':
main()