Skip to content

Instantly share code, notes, and snippets.

@celoyd
Last active October 27, 2024 20:19
Show Gist options
  • Save celoyd/cd0a827b17eb7e75d2451bc677229d63 to your computer and use it in GitHub Desktop.
Save celoyd/cd0a827b17eb7e75d2451bc677229d63 to your computer and use it in GitHub Desktop.
Simple but reasonably flexible
#!/usr/bin/env python
"""Simple slitscan generator
$ slitscan.py source slice destination
Where:
- source is a video or a directory of images;
- slice is either "c" for column or "r" for row
and an integer, e.g., r1 or c42; and
- destination is an image file.
For example:
$ slitscan.py example.mp4 r100 example.png
Or perhaps:
$ slitscan.py directoy_of_frames c0 example.tiff
To do:
- error usefully when slice is larger than source
- warn when a frame is wrong-size?
- warn if dtype seems larger than dest can handle?
- safer slice parsing; test negative indexes (ranges?!)
- combine the separate code paths, within reason
By Charlie Loyd. Last update 2024-08-30.
Distributed under the Blue Oak Model License 1.0.0:
https://blueoakcouncil.org/license/1.0.0
"""
from imageio import v3 as iio
from tqdm import tqdm
from sys import argv
from pathlib import Path
import numpy as np
def make_dst(height, width, depth, length, dtype, axis):
if axis == "r":
return np.zeros((length, width, depth), dtype=dtype)
else:
return np.zeros((height, length, depth), dtype=dtype)
src_path = Path(argv[1])
if not src_path.exists():
raise FileNotFoundError(f"{src_path} does not exist")
axis, posn = argv[2][0], int(argv[2][1:])
if axis not in ("c", "r"):
raise ValueError(f"Use c for column or r for row, e.g., r1 or c42")
dst_path = Path(argv[3])
if dst_path.exists():
raise FileExistsError(f"{dst_path} already exists")
dst = True # you don’t have to declare variables in python, they said
if src_path.is_dir():
files = sorted(list(src_path.glob("*")))
t = iio.imread(files[0])
dst = make_dst(
height=t.shape[0],
width=t.shape[1],
depth=t.shape[2],
length=len(files),
dtype=t.dtype,
axis=axis,
)
for i, f in tqdm(enumerate(files), total=len(files)):
frame = iio.imread(f)
if axis == "r":
dst[i] = frame[posn]
else:
dst[:, i] = frame[:, posn]
else:
props = iio.improps(src_path)
if props.shape[0] == 0:
raise RuntimeError(
"The video i/o library can’t tell the video’s length.\n"
"Try using ffmpeg to drop its frames to images, something like:\n"
f'$ mkdir frames; ffmpeg -i \"{src_path}\" -f image2 "frames/f%04d.png"\n'
"and run this script again with the frames folder as the input."
)
dst = make_dst(
height=props.shape[1],
width=props.shape[2],
depth=props.shape[3],
length=props.shape[0],
dtype=props.dtype,
axis=axis,
)
for i, frame in tqdm(enumerate(iio.imiter(src_path)), total=props.shape[0]):
if axis == "r":
dst[i] = frame[posn]
else:
dst[:, i] = frame[:, posn]
iio.imwrite(dst_path, dst)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment