denoising U2OS
The U2OS dataset is composed of pairs of noisy and high SNR nuclei images acquired in fluorescence microscopy. They were originally used in Weigert et al (2018) to showcase CARE denoising.
# Imports necessary to execute the code
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import tifffile
from careamics import CAREamist
from careamics.config import create_care_configuration
from careamics.utils.metrics import scale_invariant_psnr
from careamics_portfolio import PortfolioManager
from PIL import Image
Import the dataset¶
The dataset can be directly downloaded using the careamics-portfolio
package, which uses pooch
to download the data.
The CARE U2OS dataset is composed of thousands of examples organized in train and test:
- train
- low: low SNR data
- GT: high SNR data
- test
- low: low SNR data
- GT: high SNR data
# instantiate data portfolio manage
portfolio = PortfolioManager()
# and download the data
root_path = Path("./data")
download = portfolio.denoising.CARE_U2OS.download(root_path)
# path to the training data
root_path = root_path / "denoising-CARE_U2OS.unzip" / "data" / "U2OS"
train_path = root_path / "train" / "low"
target_path = root_path / "train" / "GT"
Visualize data¶
# load training image and target, and show them side by side
train_files = list(train_path.rglob("*.tif"))
train_files.sort()
target_files = list(target_path.rglob("*.tif"))
target_files.sort()
# select random example
ind = np.random.randint(len(train_files))
train_image = tifffile.imread(train_files[ind])
train_target = tifffile.imread(target_files[ind])
# plot the two images and a crop
fig, ax = plt.subplots(1, 2, figsize=(10, 5))
ax[0].imshow(train_image, cmap="gray")
ax[00].set_title("Training image")
ax[1].imshow(train_target, cmap="gray")
ax[1].set_title("Target image")
Text(0.5, 1.0, 'Target image')
Train with CAREamics¶
The easiest way to use CAREamics is to create a configuration and a CAREamist
.
Create configuration¶
The configuration can be built from scratch, giving the user full control over the various parameters available in CAREamics. However, a straightforward way to create a configuration for a particular algorithm is to use one of the convenience functions.
config = create_care_configuration(
experiment_name="care_U20S",
data_type="tiff",
axes="YX",
patch_size=(128, 128),
batch_size=32,
num_epochs=100,
)
print(config)
{'algorithm_config': {'algorithm': 'care', 'loss': 'mae', 'lr_scheduler': {'name': 'ReduceLROnPlateau', 'parameters': {}}, 'model': {'architecture': 'UNet', 'conv_dims': 2, 'depth': 2, 'final_activation': 'None', 'in_channels': 1, 'independent_channels': False, 'n2v2': False, 'num_channels_init': 32, 'num_classes': 1}, 'optimizer': {'name': 'Adam', 'parameters': {'lr': 0.0001}}}, 'data_config': {'axes': 'YX', 'batch_size': 32, 'data_type': 'tiff', 'patch_size': [128, 128], 'transforms': [{'flip_x': True, 'flip_y': True, 'name': 'XYFlip', 'p': 0.5}, {'name': 'XYRandomRotate90', 'p': 0.5}]}, 'experiment_name': 'care_U20S', 'training_config': {'checkpoint_callback': {'auto_insert_metric_name': False, 'mode': 'min', 'monitor': 'val_loss', 'save_last': True, 'save_top_k': 3, 'save_weights_only': False, 'verbose': False}, 'num_epochs': 100}, 'version': '0.1.0'}
Train¶
A CAREamist
can be created using a configuration alone, and then be trained by using the data already loaded in memory.
# instantiate a CAREamist
careamist = CAREamist(source=config)
# train
careamist.train(
train_source=train_path,
train_target=target_path,
val_percentage=0.01,
val_minimum_split=20,
)
Predict with CAREamics¶
Prediction is done with the same CAREamist
used for training, and we can use the test set.
test_path = root_path / "test" / "low"
prediction = careamist.predict(source=test_path)
Visualize the prediction¶
# Show two images
test_GT_path = root_path / "test" / "GT"
test_GT_files = list(test_GT_path.rglob("*.tif"))
test_GT_files.sort()
test_low_path = root_path / "test" / "low"
test_low_files = list(test_low_path.rglob("*.tif"))
test_low_files.sort()
test_GT = [tifffile.imread(f) for f in test_GT_files]
test_low = [tifffile.imread(f) for f in test_low_files]
# images to show
images = np.random.choice(range(len(test_GT)), 3)
fig, ax = plt.subplots(3, 3, figsize=(15, 17))
fig.tight_layout()
for i in range(3):
pred_image = prediction[images[i]].squeeze()
psnr_noisy = scale_invariant_psnr(test_GT[images[i]], test_low[images[i]])
psnr_result = scale_invariant_psnr(test_GT[images[i]], pred_image)
ax[i, 0].imshow(test_low[images[i]], cmap="gray")
ax[i, 0].title.set_text(f"Noisy\nPSNR: {psnr_noisy:.2f}")
ax[i, 1].imshow(pred_image, cmap="gray")
ax[i, 1].title.set_text(f"Prediction\nPSNR: {psnr_result:.2f}")
ax[i, 2].imshow(test_GT[images[i]], cmap="gray")
ax[i, 2].title.set_text("Ground-truth")
Compute metrics¶
psnrs = np.zeros((len(prediction), 1))
for i, (pred, gt) in enumerate(zip(prediction, test_GT)):
psnrs[i] = scale_invariant_psnr(gt, pred.squeeze())
print(f"PSNR: {psnrs.mean():.2f} +/- {psnrs.std():.2f}")
PSNR: 31.53 +/- 3.71
Create cover¶
# create a cover image
im_idx = 17
cv_image_noisy = test_low[im_idx]
cv_image_pred = prediction[im_idx].squeeze()
# create image
cover = np.zeros_like(cv_image_noisy, dtype=np.float32)
width = cover.shape[1]
# # normalize train and prediction
norm_noise = (cv_image_noisy - cv_image_noisy.min()) / (
cv_image_noisy.max() - cv_image_noisy.min()
)
norm_pred = (cv_image_pred - cv_image_pred.min()) / (
cv_image_pred.max() - cv_image_pred.min()
)
# fill in halves
cover[:, : width // 2] = norm_noise[:, : width // 2]
cover[:, width // 2 :] = norm_pred[:, width // 2 :]
# plot the single image
plt.imshow(cover)
# save the image
im = Image.fromarray(cover * 255)
im = im.convert("L")
im.save("U2OS_CARE.jpeg")