Source code for simba.video_processors.clahe_ui

import os
import threading
import time
from typing import Tuple, Union

import cv2
import numpy as np

from simba.mixins.plotting_mixin import PlottingMixin
from simba.utils.checks import check_instance
from simba.utils.enums import TextOptions
from simba.utils.errors import InvalidInputError
from simba.utils.read_write import get_video_meta_data, read_frm_of_video

WIN_NAME = 'INTERACTIVE CLAHE - HIT ESC TO RUN'
CLIP_LIMIT = 'CLIP LIMIT'
TILE_SIZE = 'TILE SIZE'
SELECT_VIDEO_FRAME = 'SHOW FRAME'

[docs]def interactive_clahe_ui(data: Union[str, os.PathLike]) -> Tuple[float, int]: """ Create a user interface using OpenCV to explore and set appropriate CLAHE settings tile size and clip limit. .. video:: _static/img/interactive_clahe_ui.webm :width: 500 :autoplay: :loop: :muted: :align: center :param Union[str, os.PathLike, np.ndarray] data: Path to a video file. :return Tuple[float, int]: Tuple containing the chosen clip limit and tile size. :example: >>> video = cv2.imread(r"D:/EPM/sample_2/video_1.mp4") >>> interactive_clahe_ui(data=video) """ global original_img, font_size, x_spacer, y_spacer, txt callback_lock = threading.Lock() last_update_time = [0] update_delay = 0.05 def _get_trackbar_values(v): global original_img, font_size, x_spacer, y_spacer, txt nonlocal callback_lock, last_update_time, update_delay current_time = time.time() if current_time - last_update_time[0] < update_delay: return if not callback_lock.acquire(blocking=False): return try: if cv2.getWindowProperty(WIN_NAME, cv2.WND_PROP_VISIBLE) < 1: return try: clip_limit = cv2.getTrackbarPos(CLIP_LIMIT, WIN_NAME) / 10.0 tile_size = cv2.getTrackbarPos(TILE_SIZE, WIN_NAME) if tile_size % 2 == 0: tile_size += 1 clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(tile_size, tile_size)) img_clahe = clahe.apply(original_img) cv2.putText(img_clahe, txt,(TextOptions.BORDER_BUFFER_X.value, TextOptions.BORDER_BUFFER_Y.value + y_spacer), TextOptions.FONT.value, font_size, (255, 255, 255), 3) cv2.imshow(WIN_NAME, img_clahe) cv2.waitKey(1) last_update_time[0] = current_time except cv2.error: pass finally: callback_lock.release() def _change_img(v): global original_img, font_size, x_spacer, y_spacer, txt current_time = time.time() if current_time - last_update_time[0] < update_delay: return if not callback_lock.acquire(blocking=False): return try: if cv2.getWindowProperty(WIN_NAME, cv2.WND_PROP_VISIBLE) < 1: return try: new_frm_id = cv2.getTrackbarPos(SELECT_VIDEO_FRAME, WIN_NAME) original_img = read_frm_of_video(video_path=data, frame_index=new_frm_id, greyscale=True) clip_limit = cv2.getTrackbarPos(CLIP_LIMIT, WIN_NAME) / 10.0 tile_size = cv2.getTrackbarPos(TILE_SIZE, WIN_NAME) if tile_size % 2 == 0: tile_size += 1 clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(tile_size, tile_size)) img_clahe = clahe.apply(original_img) cv2.putText(img_clahe, txt,(TextOptions.BORDER_BUFFER_X.value, TextOptions.BORDER_BUFFER_Y.value + y_spacer), TextOptions.FONT.value, font_size, (255, 255, 255), 3) cv2.imshow(WIN_NAME, img_clahe) cv2.waitKey(1) last_update_time[0] = current_time except cv2.error: pass finally: callback_lock.release() check_instance(source=interactive_clahe_ui.__name__, instance=data, accepted_types=(np.ndarray, str)) if isinstance(data, str): video_meta_data = get_video_meta_data(video_path=data) original_img = read_frm_of_video(video_path=data, frame_index=0, greyscale=True) else: raise InvalidInputError(msg=f'data has to be a path to a video file, but got {type(data)}', source=interactive_clahe_ui.__name__) txt = 'Hit ESC to run with chosen settings' font_size, x_spacer, y_spacer = PlottingMixin().get_optimal_font_scales(text=txt, accepted_px_width=int(video_meta_data["width"] / 2), accepted_px_height=int(video_meta_data["height"] / 15), text_thickness=3) img = np.copy(original_img) cv2.putText(img, txt, (TextOptions.BORDER_BUFFER_X.value, TextOptions.BORDER_BUFFER_Y.value + y_spacer), TextOptions.FONT.value, font_size, (255, 255, 255), 3) cv2.namedWindow(WIN_NAME, cv2.WINDOW_NORMAL) cv2.resizeWindow(WIN_NAME, video_meta_data['width'], video_meta_data['height']) cv2.imshow(WIN_NAME, img) cv2.createTrackbar(CLIP_LIMIT, WIN_NAME, 10, 300, _get_trackbar_values) cv2.createTrackbar(TILE_SIZE, WIN_NAME, 8, 64, _get_trackbar_values) cv2.createTrackbar(SELECT_VIDEO_FRAME, WIN_NAME, 0, video_meta_data['frame_count'], _change_img) while True: if cv2.getWindowProperty(WIN_NAME, cv2.WND_PROP_VISIBLE) < 1: cv2.destroyAllWindows() break k = cv2.waitKey(1) & 0xFF if k == 27: try: clip_limit = cv2.getTrackbarPos(CLIP_LIMIT, WIN_NAME) / 10.0 tile_size = cv2.getTrackbarPos(TILE_SIZE, WIN_NAME) if tile_size % 2 == 0: tile_size += 1 except cv2.error: clip_limit = 1.0 tile_size = 8 cv2.destroyAllWindows() return clip_limit, tile_size
#interactive_clahe_ui(data=r"C:\troubleshooting\cue_light\t1\project_folder\videos\2025-05-21 16-10-06_cropped.mp4") # # Function to update CLAHE # def update_clahe(x): # global img, clahe # clip_limit = cv2.getTrackbarPos('Clip Limit', 'CLAHE') / 10.0 # Scale the trackbar value # tile_size = cv2.getTrackbarPos('Tile Size', 'CLAHE') # if tile_size % 2 == 0: # tile_size += 1 # Ensure tile size is odd # clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(tile_size, tile_size)) # img_clahe = clahe.apply(img) # cv2.imshow('CLAHE', img_clahe) # # # Load an image # img = cv2.imread('/Users/simon/Downloads/PXL_20240429_222923838.jpg', cv2.IMREAD_GRAYSCALE) # # # Create a window # cv2.namedWindow('CLAHE', cv2.WINDOW_NORMAL) # # # Initialize the clip limit trackbar # cv2.createTrackbar('Clip Limit', 'CLAHE', 10, 300, update_clahe) # # # Initialize the tile size trackbar # cv2.createTrackbar('Tile Size', 'CLAHE', 8, 64, update_clahe) # # # Apply CLAHE with initial parameters # clahe = cv2.createCLAHE(clipLimit=1.0, tileGridSize=(8, 8)) # img_clahe = clahe.apply(img) # cv2.imshow('Original', img) # cv2.imshow('CLAHE', img_clahe) # # cv2.waitKey(0) # cv2.destroyAllWindows()