Skip to content
Snippets Groups Projects
Commit 6e26c0ca authored by Tamino Huxohl's avatar Tamino Huxohl
Browse files

add script to visualize 3d volumes as a slice video

parent 9f8292b5
No related branches found
No related tags found
No related merge requests found
from typing import List
import numpy as np
from mu_map.file.dicom import load_dcm_img
from mu_map.file.interfile import load_interfile_img
def load_image(filename: str) -> np.ndarray:
"""
Try to load a file as a DICOM or INTERFILE image.
:param filename: the name of the file to be loaded
:return: the image as a numpy array
:except: a ValueError is raised if the filename could not be interpreted as either format
"""
try:
return load_dcm_img(filename)
except:
pass
try:
return load_interfile_img(filename)
except:
pass
raise ValueError(f"Could not load {filename} as DICOM or INTERFILE image!")
def join_images(images: List[np.ndarray], separator: np.ndarray) -> List[np.ndarray]:
"""
Create a new image by joining all input images along a separator image.
Note that the images are joined horizontally. Thus, their shape along
the first axis must be equal.
:param images: a list of images to join
:param separator: a separator image inserted between all images
:return: a new image joined as described above
"""
res = []
for image in images:
res += [image, separator]
return np.hstack(res[:-1])
if __name__ == "__main__":
import argparse
import cv2 as cv
from mu_map.util import to_grayscale, COLOR_WHITE
parser = argparse.ArgumentParser(
description="Visualize 3D Volumes as a video of their slices"
)
parser.add_argument("images", type=str, nargs="+", help="the images to visualize")
parser.add_argument(
"--resize", type=int, default=512, help="resize images to this size"
)
parser.add_argument(
"--fps", type=int, default=25, help="frames (slices) to show per second"
)
parser.add_argument(
"--window_name", type=str, default="Slices", help="name of the displayed window"
)
args = parser.parse_args()
images = list(map(load_image, args.images))
scales = list(map(lambda image: args.resize / image.shape[1], images))
slices = [0] * len(images)
space = np.full((args.resize, 10), 239, np.uint8)
cv.namedWindow(args.window_name, cv.WINDOW_NORMAL)
cv.resizeWindow(args.window_name, 1600, 900)
timeout = 1000 // args.fps
current_timeout = timeout
while True:
_images = []
for i, (image, _slice, scale) in enumerate(zip(images, slices, scales)):
_image = to_grayscale(image[_slice], max_val=image.max(), min_val=image.min())
_image = cv.resize(_image, None, fx=scale, fy=scale)
_image = cv.putText(
_image, str(_slice + 1), (0, 30), cv.FONT_HERSHEY_SIMPLEX, 1, COLOR_WHITE, 3
)
_images.append(_image)
slices[i] = (_slice + 1) % image.shape[0]
image = join_images(_images, space)
cv.imshow(args.window_name, image)
key = cv.waitKey(current_timeout)
if key == ord("q"):
break
elif key == ord("p"):
current_timeout = 0 if current_timeout > 0 else timeout
elif key == 81 or key == 84: # back or down arrow keys
for i, (image, _slice) in enumerate(zip(images, slices)):
slices[i] = (_slice - 2) % image.shape[0]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment