| import os |
| import glob |
| import random |
| import numpy as np |
| import pandas as pd |
| import tifffile as tiff |
| import matplotlib.pyplot as plt |
| from scipy.ndimage import median_filter |
| from skimage.filters import gaussian |
| from skimage import exposure |
| from huggingface_hub import snapshot_download |
| from cellpose_omni import models, metrics, core |
|
|
| |
| |
| |
| def preprocess_w3(input_data): |
| """ W3: Cells (Brightfield) -> Blur, Median, Contrast """ |
| if isinstance(input_data, str): |
| img_raw = tiff.imread(input_data).astype(np.float32) |
| else: |
| img_raw = input_data.astype(np.float32) |
| |
| img_min, img_max = np.min(img_raw), np.max(img_raw) |
| img_8bit = ((img_raw - img_min) / (img_max - img_min) * 255).astype(np.uint8) if img_max > img_min else np.zeros(img_raw.shape, dtype=np.uint8) |
| |
| img_inverted = 255 - img_8bit |
| img_blur = gaussian(img_inverted, sigma=1, preserve_range=True) |
| img_filtered = median_filter(img_blur, size=5).astype(np.uint8) |
| p_low, p_high = np.percentile(img_filtered, (0.75, 99.25)) |
| |
| if p_low >= p_high: |
| final_img = img_filtered |
| else: |
| final_img = exposure.rescale_intensity(img_filtered, in_range=(p_low, p_high), out_range=(0, 255)).astype(np.uint8) |
| |
| |
| return (final_img / 255.0).astype(np.float32) |
|
|
| |
| |
| |
| def prepare_data(repo_id="champ7/CEllDataW3"): |
| print(f"Downloading dataset {repo_id} from Hugging Face...") |
| dataset_path = snapshot_download(repo_id=repo_id, repo_type="dataset") |
| data_dir = os.path.join(dataset_path, "combined_data") |
| |
| image_files = sorted(glob.glob(os.path.join(data_dir, "*.TIF"))) |
| seg_files = sorted(glob.glob(os.path.join(data_dir, "*_seg.npy"))) |
| |
| images, masks = [], [] |
| |
| for img_path in image_files: |
| base_name = img_path.replace(".TIF", "") |
| seg_path = base_name + "_seg.npy" |
| |
| if seg_path in seg_files: |
| img = tiff.imread(img_path).astype(np.float32) |
| images.append(img) |
| |
| seg_data = np.load(seg_path, allow_pickle=True) |
| if seg_data.shape == (): |
| seg_dict = seg_data.item() |
| mask_raw = seg_dict['masks'] |
| else: |
| mask_raw = seg_data |
| |
| |
| masks.append(mask_raw.astype(np.int32)) |
| |
| X_train, y_train = images, masks |
| |
| combined = list(zip(images, masks)) |
| random.seed(42) |
| sample_10 = random.sample(combined, min(10, len(combined))) |
| X_test, y_test = zip(*sample_10) |
| |
| return list(X_train), list(X_test), list(y_train), list(y_test) |
|
|
| |
| |
| |
| def compute_metrics(masks_true, masks_pred, threshold=0.0): |
| ap, tp, fp, fn = metrics.average_precision(masks_true, masks_pred, threshold=[threshold]) |
| |
| tp_sum = np.sum(tp) |
| fp_sum = np.sum(fp) |
| fn_sum = np.sum(fn) |
| |
| f1_score = 0.0 if (2 * tp_sum + fp_sum + fn_sum) == 0 else (2 * tp_sum) / (2 * tp_sum + fp_sum + fn_sum) |
| mean_ap = np.mean(ap) |
| |
| return f1_score, mean_ap |
|
|
| def to_numpy(data): |
| if hasattr(data, 'cpu'): |
| return data.cpu().detach().numpy() |
| elif isinstance(data, list): |
| return [to_numpy(d) for d in data] |
| elif isinstance(data, tuple): |
| return tuple(to_numpy(d) for d in data) |
| elif isinstance(data, dict): |
| return {k: to_numpy(v) for k, v in data.items()} |
| elif isinstance(data, np.ndarray) and data.dtype == object: |
| return np.array([to_numpy(d) for d in data]) |
| return data |
|
|
| |
| |
| |
| def visualize_results(raw_img, fed_img, y_true, y_pred, config_name, model_type, img_idx): |
| fig, axes = plt.subplots(1, 4, figsize=(24, 6)) |
| fig.suptitle(f"{config_name} | {model_type} | Image {img_idx}", fontsize=16, fontweight='bold') |
|
|
| axes[0].imshow(raw_img, cmap='gray') |
| axes[0].set_title("Original Image", fontsize=14) |
| axes[0].axis('off') |
|
|
| axes[1].imshow(raw_img, cmap='gray') |
| mask_true_display = np.ma.masked_where(y_true == 0, y_true) |
| axes[1].imshow(mask_true_display, cmap='nipy_spectral', alpha=0.5, interpolation='none') |
| axes[1].set_title("Original Image + GT Mask", fontsize=14) |
| axes[1].axis('off') |
|
|
| axes[2].imshow(fed_img, cmap='gray') |
| axes[2].set_title("Preprocessed Image (Fed to Model)", fontsize=14) |
| axes[2].axis('off') |
|
|
| axes[3].imshow(raw_img, cmap='gray') |
| mask_pred_display = np.ma.masked_where(y_pred == 0, y_pred) |
| axes[3].imshow(mask_pred_display, cmap='nipy_spectral', alpha=0.5, interpolation='none') |
| axes[3].set_title("Original Image + Predicted Mask", fontsize=14) |
| axes[3].axis('off') |
|
|
| plt.tight_layout() |
| plt.show() |
|
|
| |
| |
| |
| def run_pipeline(): |
| |
| use_gpu_eval = core.use_gpu() |
| channels = [0, 0] |
| base_model_name = 'cyto2' |
| |
| X_train_raw, X_test_raw, y_train, y_test = prepare_data() |
| |
| X_train_p1 = [preprocess_w3(img) for img in X_train_raw] |
| X_test_p1 = [preprocess_w3(img) for img in X_test_raw] |
|
|
| configs = [ |
| { |
| "name": "Prep 1", |
| "train_data": X_train_p1, "test_data": X_test_p1, |
| "train_kwargs": {"normalize": False, "rescale": None}, |
| "eval_kwargs": {"normalize": False, "flow_threshold": 0, "mask_threshold": -1, "rescale": None} |
| }, |
| { |
| "name": "Prep 2", |
| "train_data": X_train_raw, "test_data": X_test_raw, |
| "train_kwargs": {"normalize": True, "rescale": None}, |
| "eval_kwargs": {"normalize": True, "flow_threshold": 0, "mask_threshold": -1, "rescale": None} |
| }, |
| { |
| "name": "Prep 1 + Prep 2", |
| "train_data": X_train_p1, "test_data": X_test_p1, |
| "train_kwargs": {"normalize": True, "rescale": None}, |
| "eval_kwargs": {"normalize": True, "flow_threshold": 0, "mask_threshold": -1, "rescale": None} |
| } |
| ] |
|
|
| results = [] |
|
|
| for cfg in configs: |
| print(f"\n--- Running Configuration: {cfg['name']} ---") |
| |
| |
| |
| |
| pretrained_model = models.CellposeModel( |
| gpu=use_gpu_eval, |
| model_type=base_model_name, |
| omni=True, |
| nchan=2, |
| nclasses=2 |
| ) |
| preds_pre, _, _ = pretrained_model.eval(cfg["test_data"], channels=channels, **cfg["eval_kwargs"]) |
| |
| preds_pre = to_numpy(preds_pre) |
| f1_pre, iou_pre = compute_metrics(y_test, preds_pre, threshold=0.0) |
| |
| results.append({ |
| "Configuration": f"{cfg['name']} + Pretrained + Prediction", |
| "F1 Score": f"{f1_pre:.4f}", |
| "Mean IoU (AP)": f"{iou_pre:.4f}" |
| }) |
| |
| for viz_idx in range(min(2, len(cfg["test_data"]))): |
| visualize_results( |
| raw_img=X_test_raw[viz_idx], fed_img=cfg["test_data"][viz_idx], |
| y_true=y_test[viz_idx], y_pred=preds_pre[viz_idx], |
| config_name=cfg["name"], model_type="Pretrained Model", img_idx=viz_idx + 1 |
| ) |
| |
| |
| |
| |
| print(f"Fine-tuning {base_model_name} on CPU to guarantee zero CUDA assertion crashes...") |
| finetune_model = models.CellposeModel( |
| |
| model_type=base_model_name, |
| omni=True, |
| nchan=2, |
| nclasses=2 |
| ) |
| |
| model_path = finetune_model.train( |
| cfg["train_data"], y_train, |
| train_links=[None] * len(y_train), |
| channels=channels, |
| save_path=f"./omnipose_{cfg['name'].replace(' ', '_')}", |
| n_epochs=150, |
| learning_rate=0.1, |
| batch_size=2, |
| **cfg["train_kwargs"] |
| ) |
| |
| |
| |
| |
| custom_model = models.CellposeModel( |
| gpu=use_gpu_eval, |
| pretrained_model=model_path, |
| model_type=base_model_name, |
| omni=True, |
| nchan=2, |
| nclasses=2 |
| ) |
| preds_fine, _, _ = custom_model.eval(cfg["test_data"], channels=channels, **cfg["eval_kwargs"]) |
| |
| preds_fine = to_numpy(preds_fine) |
| f1_fine, iou_fine = compute_metrics(y_test, preds_fine, threshold=0.0) |
| |
| results.append({ |
| "Configuration": f"{cfg['name']} + Training + Prediction", |
| "F1 Score": f"{f1_fine:.4f}", |
| "Mean IoU (AP)": f"{iou_fine:.4f}" |
| }) |
| |
| for viz_idx in range(min(2, len(cfg["test_data"]))): |
| visualize_results( |
| raw_img=X_test_raw[viz_idx], fed_img=cfg["test_data"][viz_idx], |
| y_true=y_test[viz_idx], y_pred=preds_fine[viz_idx], |
| config_name=cfg["name"], model_type="Fine-tuned Model", img_idx=viz_idx + 1 |
| ) |
|
|
| |
| |
| |
| print("\n================ FINAL METRICS TABLE ================") |
| results_df = pd.DataFrame(results) |
| print(results_df.to_markdown(index=False)) |
|
|
| if __name__ == "__main__": |
| run_pipeline() |