"""The VideoStreamInterface provides an easy way to apply transforms to a video stream""" import numpy as np import panel as pn import param import skimage from PIL import Image, ImageFilter from skimage import data, filters from skimage.color.adapt_rgb import adapt_rgb, each_channel from skimage.draw import rectangle from skimage.exposure import rescale_intensity from skimage.feature import Cascade from videostream_utils import PILImageTransform, NumpyImageTransform, VideoStreamInterface pn.extension("terminal", sizing_mode="stretch_width") ACCENT = "#fef3c7" class GaussianBlur(PILImageTransform): """Gaussian Blur https://pillow.readthedocs.io/en/stable/reference/ImageFilter.html#PIL.ImageFilter.GaussianBlur """ radius = param.Integer(default=2, bounds=(0, 10)) def transform(self, image: Image): return image.filter(ImageFilter.GaussianBlur(radius=self.radius)) class GrayscaleTransform(NumpyImageTransform): """GrayScale transform https://scikit-image.org/docs/0.15.x/auto_examples/color_exposure/plot_rgb_to_gray.html """ def transform(self, image: np.ndarray): grayscale = skimage.color.rgb2gray(image[:, :, :3]) return skimage.color.gray2rgb(grayscale) class SobelTransform(NumpyImageTransform): """Sobel Transform https://scikit-image.org/docs/0.15.x/auto_examples/color_exposure/plot_adapt_rgb.html """ def transform(self, image): @adapt_rgb(each_channel) def sobel_each(image): return filters.sobel(image) return rescale_intensity(1 - sobel_each(image)) @pn.cache() def get_detector(): """Returns the Cascade detector""" trained_file = data.lbp_frontal_face_cascade_filename() return Cascade(trained_file) class FaceDetectionTransform(NumpyImageTransform): """Face detection using a cascade classifier. https://scikit-image.org/docs/0.15.x/auto_examples/applications/plot_face_detection.html """ scale_factor = param.Number(1.4, bounds=(1.0, 2.0), step=0.1) step_ratio = param.Integer(1, bounds=(1, 10)) size_x = param.Range(default=(60, 322), bounds=(10, 500)) size_y = param.Range(default=(60, 322), bounds=(10, 500)) def transform(self, image): detector = get_detector() detected = detector.detect_multi_scale( img=image, scale_factor=self.scale_factor, step_ratio=self.step_ratio, min_size=(self.size_x[0], self.size_y[0]), max_size=(self.size_x[1], self.size_y[1]), ) for patch in detected: rrr, ccc = rectangle( start=(patch["r"], patch["c"]), extent=(patch["height"], patch["width"]), shape=image.shape[:2], ) image[rrr, ccc, 0] = 200 return image component = VideoStreamInterface( transforms=[ GaussianBlur, GrayscaleTransform, SobelTransform, FaceDetectionTransform, ] ) component.video_stream.timeout=1000 component.video_stream.param.timeout.bounds=(250, 2000) pn.template.FastListTemplate( site="Awesome Panel 🤗", title="VideoStream with transforms", sidebar=[component.settings], main=[ """Try a much, much faster version here powered by Webassembly.""", component], favicon="https://sharing.awesome-panel.org/favicon.ico", accent=ACCENT, header_color="#4b5563" ).servable()