Download preprocess/visualize_patches.py from kabiriitb/rockglacierNET: direct link, hf CLI and curl.
- Browser
- Download file 10 kB
-
https://huggingface.co/kabiriitb/rockglacierNET/resolve/main/preprocess/visualize_patches.py
- Command line
-
hf download hf://kabiriitb/rockglacierNET/preprocess/visualize_patches.py
-
curl -L -o visualize_patches.py https://huggingface.co/kabiriitb/rockglacierNET/resolve/main/preprocess/visualize_patches.py
10 kB
| """ | |
| Patch visualization utilities for RockGlacierNet. | |
| Generates: | |
| outputs/patch_viz/ | |
| sample_grid_{split}.png β 4Γ8 grid of RGB+mask overlays | |
| class_distribution.png β glacier % histogram per split | |
| patch_size_distribution.png β original image H/W scatter | |
| band_histograms.png β per-band value distributions (raw) | |
| Usage (from project root): | |
| conda run -n brats python preprocess/visualize_patches.py | |
| """ | |
| import os | |
| import sys | |
| import glob | |
| import numpy as np | |
| import pandas as pd | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from preprocess.patch_config import PATCH_CONFIG | |
| import matplotlib | |
| matplotlib.use('Agg') | |
| import matplotlib.pyplot as plt | |
| import matplotlib.patches as mpatches | |
| PATCH_DIR = PATCH_CONFIG['output_dir'] | |
| SPLITS = PATCH_CONFIG['splits'] | |
| VIZ_DIR = "outputs/patch_viz" | |
| META_CSV = os.path.join(PATCH_DIR, "metadata", "patch_metadata.csv") | |
| IMG_CSV = os.path.join(PATCH_DIR, "metadata", "dataset_summary.csv") | |
| BAND_NAMES = ['B2', 'B3', 'B4', 'B8', 'B11', 'B12', | |
| 'NDVI', 'NDWI', 'NDSI', 'Elev', 'Slope', 'Aspect'] | |
| os.makedirs(VIZ_DIR, exist_ok=True) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 1. Sample grid: RGB + glacier mask overlay | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _rgb(feat: np.ndarray) -> np.ndarray: | |
| """Extract normalized RGB from raw (64,64,12) patch.""" | |
| rgb = feat[:, :, [2, 1, 0]].astype(np.float32) | |
| lo, hi = np.percentile(rgb, 2), np.percentile(rgb, 98) | |
| return np.clip((rgb - lo) / (hi - lo + 1e-8), 0, 1) | |
| def plot_sample_grid(split: str, n_cols: int = 8, n_rows: int = 4): | |
| feat_dir = os.path.join(PATCH_DIR, split, 'features') | |
| feat_files = sorted(glob.glob(os.path.join(feat_dir, '*.npy'))) | |
| if not feat_files: | |
| print(f" No patches for {split}, skipping grid.") | |
| return | |
| rng = np.random.RandomState(42) | |
| n_show = min(n_cols * n_rows, len(feat_files)) | |
| picks = rng.choice(feat_files, size=n_show, replace=False) | |
| fig, axes = plt.subplots(n_rows, n_cols, | |
| figsize=(n_cols * 2, n_rows * 2.2)) | |
| fig.suptitle(f"Sample Patches β {split} (RGB + glacier overlay)", | |
| fontsize=12, y=1.01) | |
| for ax_row in axes: | |
| for ax in ax_row: | |
| ax.axis('off') | |
| for i, fp in enumerate(sorted(picks)): | |
| row, col = divmod(i, n_cols) | |
| ax = axes[row][col] | |
| feat = np.load(fp) | |
| mask = np.load(fp.replace('features', 'masks')) | |
| rgb = _rgb(feat) | |
| ax.imshow(rgb) | |
| # Semi-transparent glacier overlay in red | |
| overlay = np.zeros((*mask.shape[:2], 4), dtype=np.float32) | |
| overlay[mask[:, :, 0] > 0.5] = [1, 0, 0, 0.45] | |
| ax.imshow(overlay) | |
| g_pct = 100.0 * (mask > 0.5).sum() / mask.size | |
| ax.set_title(f"{g_pct:.1f}%", fontsize=7, pad=2) | |
| red_patch = mpatches.Patch(color='red', alpha=0.45, label='Glacier') | |
| fig.legend(handles=[red_patch], loc='lower center', ncol=1, fontsize=9) | |
| plt.tight_layout() | |
| out = os.path.join(VIZ_DIR, f'sample_grid_{split}.png') | |
| plt.savefig(out, dpi=100, bbox_inches='tight') | |
| plt.close() | |
| print(f" Saved {out}") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 2. Class distribution histograms | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def plot_class_distribution(): | |
| if not os.path.exists(META_CSV): | |
| print(f" Metadata not found: {META_CSV}") | |
| return | |
| df = pd.read_csv(META_CSV) | |
| kept = df[df['kept_or_filtered'] == 'kept'] | |
| colors = {'train': '#2196F3', 'val': '#4CAF50', 'test': '#FF9800'} | |
| fig, axes = plt.subplots(1, 3, figsize=(15, 4), sharey=False) | |
| fig.suptitle("Glacier Coverage Distribution in Kept Patches", fontsize=12) | |
| for ax, split in zip(axes, SPLITS): | |
| sub = kept[kept['split'] == split]['glacier_percentage'] | |
| if sub.empty: | |
| ax.set_title(split); continue | |
| ax.hist(sub, bins=30, color=colors.get(split, 'gray'), | |
| edgecolor='white', linewidth=0.5) | |
| ax.set_xlabel('Glacier coverage (%)') | |
| ax.set_ylabel('Patch count') | |
| ax.set_title(f"{split} (n={len(sub)})\nmean={sub.mean():.1f}% median={sub.median():.1f}%") | |
| ax.axvline(sub.mean(), color='black', linestyle='--', linewidth=1, label='mean') | |
| ax.legend(fontsize=8) | |
| plt.tight_layout() | |
| out = os.path.join(VIZ_DIR, 'class_distribution.png') | |
| plt.savefig(out, dpi=100, bbox_inches='tight') | |
| plt.close() | |
| print(f" Saved {out}") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 3. Image size scatter | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def plot_image_sizes(): | |
| if not os.path.exists(IMG_CSV): | |
| print(f" Image summary not found: {IMG_CSV}") | |
| return | |
| df = pd.read_csv(IMG_CSV) | |
| colors = {'train': '#2196F3', 'val': '#4CAF50', 'test': '#FF9800'} | |
| fig, ax = plt.subplots(figsize=(7, 6)) | |
| for split in SPLITS: | |
| sub = df[df['split'] == split] | |
| ax.scatter(sub['original_width'], sub['original_height'], | |
| alpha=0.5, s=20, label=split, color=colors.get(split, 'gray')) | |
| patch_size = PATCH_CONFIG['patch_size'] | |
| ax.axvline(patch_size, color='red', linestyle='--', linewidth=1, | |
| label=f'patch_size={patch_size}') | |
| ax.axhline(patch_size, color='red', linestyle='--', linewidth=1) | |
| ax.set_xlabel('Original image width (px)') | |
| ax.set_ylabel('Original image height (px)') | |
| ax.set_title('Original Image Size Distribution') | |
| ax.legend(fontsize=9) | |
| plt.tight_layout() | |
| out = os.path.join(VIZ_DIR, 'patch_size_distribution.png') | |
| plt.savefig(out, dpi=100, bbox_inches='tight') | |
| plt.close() | |
| print(f" Saved {out}") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 4. Per-band histograms from a random sample of patches | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def plot_band_histograms(n_samples: int = 200): | |
| feat_files = [] | |
| for split in SPLITS: | |
| feat_files += glob.glob(os.path.join(PATCH_DIR, split, 'features', '*.npy')) | |
| if not feat_files: | |
| print(" No patches found for band histograms.") | |
| return | |
| rng = np.random.RandomState(0) | |
| picks = rng.choice(feat_files, size=min(n_samples, len(feat_files)), replace=False) | |
| # Collect band data | |
| band_data = [[] for _ in range(12)] | |
| for fp in picks: | |
| feat = np.load(fp) # (64, 64, 12) raw | |
| for b in range(12): | |
| band_data[b].append(feat[:, :, b].flatten()) | |
| fig, axes = plt.subplots(3, 4, figsize=(16, 10)) | |
| fig.suptitle(f"Per-Band Value Distributions (raw, {len(picks)} random patches)", fontsize=12) | |
| for b, ax in enumerate(axes.flatten()): | |
| vals = np.concatenate(band_data[b]) | |
| # Clip extreme outliers for readability | |
| lo, hi = np.percentile(vals, 1), np.percentile(vals, 99) | |
| vals_clip = vals[(vals >= lo) & (vals <= hi)] | |
| ax.hist(vals_clip, bins=60, color='#1976D2', edgecolor='none', alpha=0.8) | |
| ax.set_title(BAND_NAMES[b], fontsize=9) | |
| ax.set_xlabel('Value', fontsize=7) | |
| ax.set_ylabel('Count', fontsize=7) | |
| ax.tick_params(labelsize=7) | |
| ax.text(0.97, 0.93, f"ΞΌ={vals.mean():.3f}\nΟ={vals.std():.3f}", | |
| transform=ax.transAxes, ha='right', va='top', fontsize=7, | |
| bbox=dict(boxstyle='round', fc='white', alpha=0.7)) | |
| plt.tight_layout() | |
| out = os.path.join(VIZ_DIR, 'band_histograms.png') | |
| plt.savefig(out, dpi=100, bbox_inches='tight') | |
| plt.close() | |
| print(f" Saved {out}") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Main | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def main(): | |
| print("Generating patch visualizationsβ¦") | |
| print("\n1. Sample gridsβ¦") | |
| for split in SPLITS: | |
| plot_sample_grid(split) | |
| print("\n2. Class distributionβ¦") | |
| plot_class_distribution() | |
| print("\n3. Image size scatterβ¦") | |
| plot_image_sizes() | |
| print("\n4. Band histogramsβ¦") | |
| plot_band_histograms() | |
| print(f"\nAll figures saved to {VIZ_DIR}/") | |
| if __name__ == '__main__': | |
| main() | |