-
-
Save VolkerH/8b959496092e3f48e6f69ba7219c7004 to your computer and use it in GitHub Desktop.
texture live update from webcam
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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