CellSamCells / omnipose.py
champ7's picture
Create omnipose.py
bc8bbcf verified
Raw
History Blame Contribute Delete
10.2 kB
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
# ==========================================
# 1. Custom Preprocessing (Prep 1)
# ==========================================
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)
# Standardize to 0.0 - 1.0 floats
return (final_img / 255.0).astype(np.float32)
# ==========================================
# 2. Data Preparation
# ==========================================
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
# Convert to standard 32-bit integer labels
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)
# ==========================================
# 3. Metrics & Utilities
# ==========================================
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
# ==========================================
# 4. Visualization Helper (4 Panels)
# ==========================================
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()
# ==========================================
# 5. Pipeline Execution
# ==========================================
def run_pipeline():
# Use GPU for fast inference/evaluation
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']} ---")
# ------------------------------------------
# A. Pretrained Model Evaluation (Runs on GPU if available)
# ------------------------------------------
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
)
# ------------------------------------------
# B. Fine-tuning Model (gpu=False BYPASSES CUDA LOSS ASSERTIONS COMPLETELY)
# ------------------------------------------
print(f"Fine-tuning {base_model_name} on CPU to guarantee zero CUDA assertion crashes...")
finetune_model = models.CellposeModel(
#gpu=False, # <--- THIS REMOVES THE ASSERTION PROBLEM ENTIRELY
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"]
)
# ------------------------------------------
# C. Evaluate Fine-Tuned Model (Evaluates back on GPU)
# ------------------------------------------
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
)
# ==========================================
# 6. Final Output Compilation
# ==========================================
print("\n================ FINAL METRICS TABLE ================")
results_df = pd.DataFrame(results)
print(results_df.to_markdown(index=False))
if __name__ == "__main__":
run_pipeline()