Skip to content

Commit

Permalink
Update IO tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
sitic committed May 24, 2024
1 parent e69f63f commit 5a783ae
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 46 deletions.
160 changes: 115 additions & 45 deletions docs/tutorials/io.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"* .dat (MultiRecorder)\n",
"* .npy (NumPy array)\n",
"* .mat (MATLAB), loads the first field in the file\n",
"* .mp4, .avi, .mov, ... (digital video files)\n",
"\n",
"Additional file formats will be added in the future (and upon request). All files can be imported using the same {func}`load_video` function, with which it is also possible to load only a specific number of frames or range of the data (e.g. from a specific frame to another), see below. \n",
"\n",
Expand Down Expand Up @@ -173,14 +174,14 @@
"```\n",
":::\n",
"\n",
":::{dropdown} Digital video (.mp4, .avi, ..)\n",
"optimap can import digital video files (.mp4, .avi, .mov, ...):\n",
":::{dropdown} Digital video files (.mp4, .avi, .mov, ...)\n",
"optimap can import .mp4, .avi, .mov and other similar digital video files using the same {func}`load_video` function:\n",
"\n",
"```python\n",
"video = om.load_video(\"example.mp4\")\n",
"```\n",
"\n",
"by default only the luminance channel of the input video is imported. To load the color video use\n",
"by default only the luminance channel of the input video is imported. To load the color video (RGB) use\n",
"\n",
"```python\n",
"video = om.load_video(\"example.mp4\", as_grey=False)\n",
Expand Down Expand Up @@ -255,26 +256,6 @@
"````"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Importing Images and Masks\n",
"\n",
"Individual images (.tif, .png, .jpg, .npy, ...) can be imported using {func}`load_image`:\n",
"\n",
"```python\n",
"image = om.load_image(\"example.tif\")\n",
"```\n",
"the `as_grey` argument can be used to convert the image to a grayscale image (if it is not already).\n",
"\n",
"Segmentation masks can be imported using {func}`load_mask`:\n",
"```python\n",
"mask = om.load_mask(\"mask.png\")\n",
"```\n",
"See [Tutorial 3: Masking / Segmentation](/tutorials/mask) for more details on how to load, create and use masks."
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -384,7 +365,7 @@
"source": [
"With the normalization (the subtraction of the minimum and the division by the maximum) in the code snippet above it is ensured that no values are below 0 or above 255 (or 65536, respectively).\n",
"\n",
"### Video Export\n",
"### Exporting Videos\n",
"\n",
"The main purpose of exporting videos is to generate or render videos in a file format (.mp4) that can be played with an external video player application (e.g. Quicktime, VLC, Windows Media Player etc.) or be included in slideshows (e.g. Powerpoint). You can export videos in several ways: \n",
"\n",
Expand Down Expand Up @@ -473,7 +454,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Here, only every 2nd frame from frames 100-500 are exported to a video with a framerate of 30fps, `vmin` and `vmax` define the dynamic range of pixel values (0.1 is black and 0.9 white with the grayscale colormap) and the `magma` colormap.\n",
"Here, the video is exported with a framerate of 15fps, `vmin` and `vmax` are used define the dynamic range of pixel values. The `step` parameter can be used to only export every n-th frame.\n",
"\n",
"{func}`video.export_video_with_overlay` can be used to overlay two videos on top of each other. For instance, a pixel-wise normalized video which shows action potential or calcium waves, see [Tutorial 2](signal_extraction.ipynb), on top of the original grayscale video:"
]
Expand All @@ -489,7 +470,7 @@
"outputs": [],
"source": [
"overlay = om.video.normalize_pixelwise(video)\n",
"om.video.export_video_with_overlay(\"video.mp4\", video, overlay=overlay, fps=15)"
"om.export_video_with_overlay(\"video.mp4\", video, overlay=overlay, fps=15)"
]
},
{
Expand All @@ -515,7 +496,7 @@
"overlay_motion = om.video.temporal_difference(video, 3)\n",
"overlay_motion = om.video.normalize_pixelwise(overlay_motion, ymin=1, ymax=-1)\n",
"\n",
"om.video.export_video_with_overlay(\"video.mp4\", video_warped, overlay=overlay, alpha=alpha, fps=15)\n",
"om.export_video_with_overlay(\"video.mp4\", video_warped, overlay=overlay, alpha=alpha, fps=15)\n",
"Video(filename='video.mp4', embed=True, html_attributes=\"controls autoplay loop\")"
]
},
Expand Down Expand Up @@ -625,7 +606,31 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Saving / Exporting Images and Masks\n",
"## Images and Masks\n",
"\n",
"### Importing Images & Masks\n",
"\n",
"Individual images (.tif, .png, .jpg, .npy, ...) can be imported using {func}`load_image`:\n",
"\n",
"```python\n",
"image = om.load_image(\"example.tif\")\n",
"```\n",
"the `as_grey` argument can be used to convert the image to a grayscale image (if it is not already).\n",
"\n",
"Segmentation masks can be imported using {func}`load_mask`:\n",
"```python\n",
"mask = om.load_mask(\"mask.png\")\n",
"```\n",
"See [Tutorial 3: Masking / Segmentation](/tutorials/mask) for more details on how to load, create and use masks."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Saving or Exporting Images & Masks\n",
"\n",
"As for videos, we differentiate between saving and exporting. The save functions aim to prevent any loss of precision such that the resulting file can be loaded with {func}`load_image`. The export function on the other hand support colormaps and should be used when the resulting file will be used for presentation.\n",
"\n",
"Images can be saved using {func}`save_image`:\n",
"\n",
Expand All @@ -634,32 +639,33 @@
"```\n",
"\n",
"The following file formats and image data types are supported:\n",
"* PNG: .png, 8-bit or 16-bit unsigned images\n",
"* TIFF: .tif/.tiff, 8-bit unsigned, 16-bit unsigned, 32-bit float, or 64-bit float images\n",
"* NumPy: .npy, all data types\n",
"* PNG: .png, 8-bit or 16-bit unsigned per image channel\n",
"* TIFF: .tif/.tiff, 8-bit unsigned, 16-bit unsigned, 32-bit float, or 64-bit float images\n",
"* JPEG: .jpeg/.jpg, 8-bit unsigned\n",
"* Windows bitmaps: .bmp, 8-bit unsigned\n",
"\n",
":::{admonition} Images appear black in viewer\n",
":class: warning\n",
"The function {func}`save_image` aims to export the image in the same data format (e.g. 16-bit or floating point) to prevent loss of precision. This is sometimes unwanted, as it can make the images appear black in some image viewers. For the widest compatibility, convert images to 8-bit unsigned (uint8).\n",
"The image data is saved as it is, without any normalization or scaling.\n",
"\n",
":::{admonition} Images appear black in another image viewer\n",
":class: note\n",
"\n",
"Standard external image viewers can often not handle 16-bit unsigned or 32-bit float image data, which can make images saved with {func}`save_image` appear black. Use {func}`export_image` instead to save images in a format that can be viewed with standard image viewers if the image will not be further processed.\n",
":::\n",
"\n",
"To export images use {func}`export_image`:\n",
"\n",
"Setting the flag `compat` converts the input automatically to uint8 using {func}`image.normalize`\n",
"```python\n",
"om.save_image(\"example.png\", image, compat=True)\n",
"```\n",
"The option `compat=True` is equivalent to\n",
"```python\n",
"image = om.image.normalize(image, dtype=\"uint8\")\n",
"om.save_image(\"example.png\", image)\n",
"om.export_image(\"example.png\", image)\n",
"```\n",
"Note that {func}`image.normalize` uses the minimum and maximum value of the image by default for the normalization to uint8 (integer values 0-255). It is often advised to set the input data range manually using `vmin` and `vmax`:\n",
"\n",
"For grayscale images {func}`export_image` uses the minimum and maximum value of the image by default for the normalization to an 8-bit image (integer values 0-255). It is often advised to set the input data range manually using `vmin` and `vmax`:\n",
"\n",
"```python\n",
"image = om.image.normalize(image, vmin=0, vmax=1, dtype=\"uint8\")\n",
"om.save_image(\"example.png\", image)\n",
"om.export_image(\"example.png\", image, vmin=0, vmax=1, cmap=\"gray\")\n",
"```\n",
"This example here maps the value range [0, 1] to [0, 255]. Alternatively normalize the whole video at once using `video.normalize`.\n",
":::"
"\n",
"In this example the value range [0, 1] is mapped to [0, 255]."
]
},
{
Expand All @@ -672,6 +678,70 @@
"om.save_mask(\"mask.png\", mask)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exporting Plots\n",
"\n",
"All plotting functions such as {func}`show_image`, {func}`show_mask`, {func}`show_traces` etc are based on matplotlib. To export the output click the save icon in the plot window, or use {func}`matplotlib.pyplot.savefig`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"skip-execution"
]
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"om.show_image(image)\n",
"plt.savefig(\"image.png\", bbox_inches='tight')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"or equivalently:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ax = om.show_image(image)\n",
"ax.figure.savefig(\"image.png\", bbox_inches='tight')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All plotting accept a {class}`matplotlib.axes.Axes` as input to create subplots figures:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"skip-execution"
]
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(2)\n",
"om.show_image(image, ax=axs[0])\n",
"om.show_traces(traces, ax=axs[1])\n",
"fig.savefig(\"image.png\", dpi=300)"
]
}
],
"metadata": {
Expand Down
4 changes: 3 additions & 1 deletion optimap/image/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def save_mask(filename, mask, image=None, **kwargs):
def save_image(filename, image: np.ndarray, compat=False, **kwargs):
"""Save an image to a file. Makes best effort to avoid data precision loss, use {func}`export_image` to export images for publications.
The file format is inferred from the filename extension.
The image data is saved as it is, without any normalization or scaling.
The following file formats and image data types are supported:
* NumPy: .npy, all data types
Expand All @@ -221,6 +221,8 @@ def save_image(filename, image: np.ndarray, compat=False, **kwargs):
* JPEG: .jpeg/.jpg, 8-bit unsigned
* Windows bitmaps: .bmp, 8-bit unsigned
The file format is inferred from the filename extension.
Uses :func:`numpy.save` internally if the file extension is ``.npy`` and :func:`cv2.imwrite` otherwise.
Parameters
Expand Down

0 comments on commit 5a783ae

Please sign in to comment.