Skip to content

Instantly share code, notes, and snippets.

@VolkerH
Created December 6, 2020 12:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VolkerH/8b959496092e3f48e6f69ba7219c7004 to your computer and use it in GitHub Desktop.
Save VolkerH/8b959496092e3f48e6f69ba7219c7004 to your computer and use it in GitHub Desktop.
texture live update from webcam
# demonstrate how to find the vispy 3D Texture for a layer
# and how to update part of it
import numpy as np
import napari
from napari.qt.threading import thread_worker
from pathlib import Path
import time
import tifffile
from itertools import cycle
import cv2
# The texture slice of the incoming camera image
# is highlighted by adding a fixed offset to the
# grevalues. Adjust this offset to find something
# you find visually pleasing.
capture = cv2.VideoCapture(0)
highlight_offset = 0
nz = 100
# get an initial frame to determine shape
ret, frame = capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ny, nx = gray.shape
print(f'Stack has shape (nz, ny, nx) = ({nz}, {ny}, {nx}).')
# blank volume to initialize the image layer before
# images come in from the camera worker thread
blank = np.zeros_like(np.array(nz * [gray]))
# build the affine matrix for deskewing the
# sample data set from Talley Lambert
deskew = np.eye(4)
# deskew[2, 0] = 4.086
@thread_worker
def camera_simulator():
"""Simulate reading slice images that are written
to disk by some camera acquisition software.
Here, we just cycle through a list of images,
each image representing one slice of a stack.
In practice you may want to implement some
kind of watchdog here, that monitors a folder
for incoming images and returns them.
Returns:
(zslice, previous, current)
zslice: int, current zslice number
previous: np.ndarray, previous image
current: np.ndarray, current image
"""
count = -1
global gray
previous = np.zeros_like(gray)
current = previous
for chfiles in cycle([1]):
if count % nz == nz - 1:
# simulate some delay between
# subsequent stacks
time.sleep(0.5)
else:
# some limit on framerate
time.sleep(0.00000001)
previous = current
ret, frame = capture.read()
current = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#current = cv2.equalizeHist(current)
print(np.max(current))
current[current < 130] = 0
count += 1
yield count % nz, previous, current
with napari.gui_qt():
# Initialize viewer with a blank volume
viewer = napari.Viewer(
ndisplay=3, title="Live volume acquisition visualization"
)
webcam_l = viewer.add_image(
blank,
name="webcam",
scale=(20, 1, 1),
colormap='gray',
blending='additive',
)
vispy_webcam_layer = viewer.window.qt_viewer.layer_to_visual[webcam_l]
volume = vispy_webcam_layer._layer_node.get_node(3)
def update_slice_vol(params):
"""Callback that updates the texture buffers when the
worker thread yields new images for the channels.
The current slice is highlighted by adding a fixed offset."""
zslice, previous, current = params
texture = volume._tex
if zslice < nz - 1:
texture.set_data(
np.array([previous, current + highlight_offset]),
offset=(zslice, 0, 0),
)
elif zslice == nz - 1:
texture.set_data(
np.array([current, current]), offset=(zslice - 1, 0, 0)
)
volume.update()
worker = camera_simulator()
worker.yielded.connect(update_slice_vol)
worker.start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment