Source code for crappy.blocks.displayer

# coding: utf-8

import numpy as np
from .block import Block
from .._global import CrappyStop
from .._global import OptionalModule

try:
  from PIL import ImageTk, Image
except (ModuleNotFoundError, ImportError):
  ImageTk = OptionalModule("pillow")
  Image = OptionalModule("pillow")

try:
  import matplotlib.pyplot as plt
except (ModuleNotFoundError, ImportError):
  plt = OptionalModule("matplotlib")

try:
  import cv2
except (ModuleNotFoundError, ImportError):
  cv2 = OptionalModule("opencv-python")

try:
  import tkinter as tk
except (ModuleNotFoundError, ImportError):
  tk = OptionalModule("tkinter")


[docs]class Displayer(Block): """Simple image displayer using :mod:`cv2` or :mod:`matplotlib`. Important: One displayer can only display images from one camera. """ def __init__(self, framerate: float = 5, backend: str = 'cv', title: str = 'Displayer') -> None: Block.__init__(self) self.niceness = 10 if framerate is None: self.delay = 0 else: self.delay = 1. / framerate # Framerate (fps) self.title = title if backend.lower() in ['cv', 'opencv']: self.prepare = self.prepare_cv self.loop = self.loop_cv self.begin = self.begin_cv self.finish = self.finish_cv elif backend.lower() in ['matplotlib', 'mpl']: self.prepare = self.prepare_mpl self.loop = self.loop_mpl self.begin = self.begin_mpl self.finish = self.finish_mpl elif backend.lower() in ['tk', 'tkinter']: self.prepare = self.prepare_tk self.loop = self.loop_tk self.begin = self.begin_tk self.finish = self.finish_tk else: raise AttributeError("Unknown backend: " + str(backend)) # Matplotlib @staticmethod def prepare_mpl() -> None: plt.ion() fig = plt.figure() fig.add_subplot(111) def begin_mpl(self) -> None: self.inputs[0].clear() @staticmethod def cast_8bits(f: np.ndarray): m = np.amax(f) i = 0 while m >= 2 ** (8 + i): i += 1 return (f / (2 ** i)).astype(np.uint8) def loop_mpl(self) -> None: data = self.inputs[0].recv_delay(self.delay)['frame'][-1] plt.clf() plt.imshow(data, cmap='gray') plt.pause(0.001) plt.show() @staticmethod def finish_mpl() -> None: plt.close('all') # OpenCV def prepare_cv(self) -> None: try: flags = cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO # WINDOW_KEEPRATIO is not implemented in all opencv versions... except AttributeError: flags = cv2.WINDOW_NORMAL cv2.namedWindow(self.title, flags) def begin_cv(self) -> None: self.inputs[0].clear() def loop_cv(self) -> None: data = self.inputs[0].recv_delay(self.delay)['frame'][-1] if data.dtype != np.uint8: if data.max() >= 256: data = self.cast_8bits(data) else: data = data.astype(np.uint8) cv2.imshow(self.title, data) cv2.waitKey(1) @staticmethod def finish_cv() -> None: cv2.destroyAllWindows() # TKinter def resize(self, img: np.ndarray): return cv2.resize(img, (self.w, self.h)) def check_resized(self) -> None: new = self.imglabel.winfo_height() - 2, self.imglabel.winfo_width() - 2 if sum([abs(i - j) for i, j in zip(new, (self.h, self.w))]) >= 5: if new[0] > 0 and new[1] > 0: self.h, self.w = new ratio = min(self.h / self.img_shape[0], self.w / self.img_shape[1]) self.h = int(self.img_shape[0] * ratio) self.w = int(self.img_shape[1] * ratio) def prepare_tk(self) -> None: self.root = tk.Tk() self.root.protocol("WM_DELETE_WINDOW", self.end) self.imglabel = tk.Label(self.root) self.imglabel.pack() # self.imglabel.grid(row=0, column=0, sticky=tk.N + tk.E + tk.S + tk.W) self.imglabel.pack(expand=1, fill=tk.BOTH) self.h = 480 self.w = 640 def begin_tk(self) -> None: self.inputs[0].clear() data = self.inputs[0].recv_delay(self.delay)['frame'][-1] self.img_shape = data.shape self.check_resized() self.go = True def loop_tk(self) -> None: if not self.go: raise CrappyStop data = self.inputs[0].recv_delay(self.delay)['frame'][-1] self.img_shape = data.shape self.check_resized() if data.dtype != np.uint8: if data.max() >= 256: data = self.cast_8bits(data) else: data = data.astype(np.uint8) cimg = ImageTk.PhotoImage(Image.fromarray(self.resize(data))) self.imglabel.configure(image=cimg) self.root.update() def end(self) -> None: self.go = False def finish_tk(self) -> None: self.root.destroy()