Utils.Display

Fill in a module description here
from nbdev.showdoc import *
from nbdev.showdoc import *
from fastcore.test import *
import inspect
def _fig_bounds(x):
    r = x//32
    return min(5, max(1,r))
from fastcore.utils import *
import cv2
import numpy as np
from imutils import resize
from PIL import Image
import matplotlib
import matplotlib.pyplot as plt
import moviepy.editor as mvp
from moviepy.video.io.ffmpeg_writer import FFMPEG_VideoWriter
import logging
import UAV.params as params
from UAV.utils.display import *
GStreamer is not installed

show_image

 show_image (im, ax=None, figsize=None, title=None, text=None,
             fontsize=12, ctx=None, rgb2bgr:bool=False, **kwargs)

Show a PIL or PyTorch image on ax.

Type Default Details
im
ax NoneType None if None, a new figure is created
figsize NoneType None if None, the figure size is set to min of 5 and max of 1/32 of the image size
title NoneType None title of the image
text NoneType None text to be written on image
fontsize int 12 fontsize of text
ctx NoneType None context
rgb2bgr bool False convert from/to RGB
kwargs
Returns plt.Axes return matplotlib axis
im2 = np.array(Image.open(TEST_IMAGE))
ax = show_image(im2, text='dog', figsize=(3,3))

ax = show_image(im2, text='dog', figsize=(3,3), rgb2bgr=True)

im2 = np.array(Image.open(TEST_IMAGE))
im2 = puttext(im2, 'dog')
ax = show_image(im2)

_,axs = plt.subplots(1,4,figsize=(12,4))
for i,ax in enumerate(axs): show_image(im2, ax=ax, title=f'Copy {i+1}')


ScrollingLog.update

 ScrollingLog.update (message:str, index=None)

Add a message to the log, if index is specified, update the message at the index

Type Default Details
message str add a message to the log
index NoneType None index of the message to be updated

ScrollingLog.draw

 ScrollingLog.draw (image, font=0)

Draw the log on the image

Run some tests

image = np.array(Image.open(TEST_IMAGE))
log = ScrollingLog()
test_eq(log.draw(image), None)   # runs with no log present
for i in range(10):
    log.update(f"Message {i}")

test_eq(log.log[0], "Message 5")
test_eq(log.log[-1], "Message 9")
test_eq(len(log.log), 5)
log.draw(image)
ax = show_image(image)


ScrollingLogHandler.set_filter

 ScrollingLogHandler.set_filter (_filter:str)

Set the filter for the log message

# Standard Setting up logging
logging.basicConfig(format='%(asctime)-8s,%(msecs)-3d %(levelname)5s [%(filename)10s:%(lineno)3d] %(message)s',
                        datefmt='%H:%M:%S',
                        level=params.LOGGING_LEVEL)  # Todo add this to params
logger = logging.getLogger(params.LOGGING_NAME)

log = ScrollingLog(bg_color=(0,0,0))
handler_log = ScrollingLogHandler(log, logger, _filter='AIR')

# Example usage:
logger.info("AIR: This is an info log.")
logger.warning("This is a warning log.")
logger.error("AIR: This is an error log.")
logger.error("This is an error log.")
logger.warning("AIR:This is an warning log.")
# Display the logs using OpenCV or your desired method
# image = cv2.imread("path_to_image.jpg")
image = np.array(Image.open(TEST_IMAGE))
log.draw(image)
ax = show_image(image[:200,:600], figsize=(5,3))

test_eq(len(log.log), 3)   # there are 3 AIR messages in the log above
INFO   | uav_log         | 03.735 | 817836736.py: 11 | MainThread         | AIR: This is an info log.
WARNIN | uav_log         | 03.737 | 817836736.py: 12 | MainThread         | This is a warning log.
ERROR  | uav_log         | 03.738 | 817836736.py: 13 | MainThread         | AIR: This is an error log.
ERROR  | uav_log         | 03.738 | 817836736.py: 14 | MainThread         | This is an error log.
WARNIN | uav_log         | 03.738 | 817836736.py: 15 | MainThread         | AIR:This is an warning log.

handler_log.set_filter('')
logger.error("error1 .")
logger.error("error2 .")
image = np.array(Image.open(TEST_IMAGE))
log.draw(image)
ax = show_image(image[:200,:600], figsize=(5,3))
test_eq(len(log.log), 5)
ERROR  | uav_log         | 03.887 | 2590345404.py:  2 | MainThread         | error1 .
ERROR  | uav_log         | 03.888 | 2590345404.py:  3 | MainThread         | error2 .

Example of use ScrollingLog with index

# Simulate sequence of images

image = np.array(Image.open(TEST_IMAGE))
def test_log(image, max_lines=3, font_scale=2.0, index=None, bg_color=None):
    log = ScrollingLog(max_lines=max_lines, font_scale=font_scale, bg_color=bg_color)
    
    # Update log messages
    for i in range(6):
        log.update(f"Message {i}")
    log.update(f"Mes {i+1}")
    
    _,axs = plt.subplots(1,3,figsize=(16,8))
    for i,ax in enumerate(axs.flatten()): 
        img_copy = image.copy()
        log.update(f"Message {i + 7}", index=index)
        log.draw(img_copy)
        # just show the top left corner of the image
        img_copy = img_copy[:img_copy.shape[0]//2, :img_copy.shape[1]//2]
        show_image(img_copy, ax=ax, title=f'Copy {i+1}')

test_log(image, max_lines=3, font_scale=2.0, index=None, bg_color=(0,0,255))

test_log(image, max_lines=5, font_scale=1.4, index=None, bg_color=(0,0,0))

test_log(image, max_lines=8, font_scale=1.0, index=None)

test_log(image, max_lines=5, font_scale=1.4, index=6, bg_color=(0,0,0))
Warning:  0 <= index < len(self.log)
Warning:  0 <= index < len(self.log)
Warning:  0 <= index < len(self.log)

from UAV.utils.display import *

VideoWriter.add

 VideoWriter.add (img:numpy.ndarray)

Add an image to the video

Type Details
img np.ndarray image to be added
Returns None

VideoWriter.close

 VideoWriter.close ()

VideoWriter.show

 VideoWriter.show (**kw)

Show the video

import cv2
from UAV.utils.display import VideoWriter, ScrollingLog, ScrollingLogHandler, puttext, show_image
import numpy as np
from PIL import Image
from fastcore.test import *
import logging

# uncomment below to run logging on console
# logging.basicConfig(format=
#                     '%(asctime)-8s,%(msecs)-3d %(levelname)5s [%(filename)10s:%(lineno)3d] %(message)s',
#                     datefmt='%H:%M:%S',
#                     level=logging.INFO)  

logger = logging.getLogger(params.LOGGING_NAME) # Todo add this to params
logger.setLevel(params.LOGGING_LEVEL)
log = ScrollingLog(bg_color=(0,0,0))
handler_log = ScrollingLogHandler(log, logger)
logger.info(f"Hello World")

img = np.array(Image.open(TEST_IMAGE))
framecounter = 0
with VideoWriter("images/videowriter_test.mp4", 5.0) as video:
# if True:
    for i in range(20):
        puttext(img, f"Frame: {framecounter}", pos=(700,80))
        logger.info(f"Frame: {framecounter}")
        log.draw(img)
        # cv2.imshow('image', img)
        k = cv2.waitKey(100)
        if k == 27 or k == ord('q') or k == ord('Q'):
            break
        video.add(img)
        framecounter += 1
# cv2.destroyAllWindows()
ax=show_image(img)

video.show(width=500)
test_eq(framecounter, 20)
INFO   | uav_log         | 04.928 | 1743171834.py: 19 | MainThread         | Hello World
INFO   | uav_log         | 04.934 | 1743171834.py: 27 | MainThread         | Frame: 0
INFO   | uav_log         | 04.939 | 1743171834.py: 27 | MainThread         | Frame: 1
INFO   | uav_log         | 04.953 | 1743171834.py: 27 | MainThread         | Frame: 2
INFO   | uav_log         | 04.960 | 1743171834.py: 27 | MainThread         | Frame: 3
INFO   | uav_log         | 04.965 | 1743171834.py: 27 | MainThread         | Frame: 4
INFO   | uav_log         | 04.972 | 1743171834.py: 27 | MainThread         | Frame: 5
INFO   | uav_log         | 04.976 | 1743171834.py: 27 | MainThread         | Frame: 6
INFO   | uav_log         | 04.982 | 1743171834.py: 27 | MainThread         | Frame: 7
INFO   | uav_log         | 04.987 | 1743171834.py: 27 | MainThread         | Frame: 8
INFO   | uav_log         | 04.992 | 1743171834.py: 27 | MainThread         | Frame: 9
INFO   | uav_log         | 04.998 | 1743171834.py: 27 | MainThread         | Frame: 10
INFO   | uav_log         | 05.004 | 1743171834.py: 27 | MainThread         | Frame: 11
INFO   | uav_log         | 05.009 | 1743171834.py: 27 | MainThread         | Frame: 12
INFO   | uav_log         | 05.014 | 1743171834.py: 27 | MainThread         | Frame: 13
INFO   | uav_log         | 05.020 | 1743171834.py: 27 | MainThread         | Frame: 14
INFO   | uav_log         | 05.025 | 1743171834.py: 27 | MainThread         | Frame: 15
INFO   | uav_log         | 05.030 | 1743171834.py: 27 | MainThread         | Frame: 16
INFO   | uav_log         | 05.036 | 1743171834.py: 27 | MainThread         | Frame: 17
INFO   | uav_log         | 05.041 | 1743171834.py: 27 | MainThread         | Frame: 18
INFO   | uav_log         | 05.047 | 1743171834.py: 27 | MainThread         | Frame: 19
Writing video to /home/jn/PycharmProjects/UAV/nbs/api/images/videowriter_test.mp4 at 5.0 fps.
Video: /home/jn/PycharmProjects/UAV/nbs/api/images/videowriter_test.mp4


doc_class

 doc_class (cls)

Document all the public methods in a class

# show_doc(Example)
import asyncio
class Example:
    """This is an example class."""
    def __init__(self, param1:float, # param 1
                 param2:str): # param 2
        pass
    def _method_a(self, param1:int, # param 1
                 param2: int):  # param 2
        "This is method A"
        pass
    def method_a(self, param1:int, # the param 1
                 param2: int):  # the param 2
        "This is method A"
        pass
    async def method_b(self, param1:int, # the param 1
                 param2: int):  # the param 2
        "This is method B"
        pass

Example of use doc_class

from UAV.utils.display import doc_class
doc_class(Example)

Example.method_a

 Example.method_a (param1:int, param2:int)

This is method A

Type Details
param1 int the param 1
param2 int the param 2

Example.method_b

 Example.method_b (param1:int, param2:int)

This is method B

Note: async function

DocmentTbl(Example)
Type Details
param1 float param 1
param2 str param 2
inspect.signature(Example.method_b)
<Signature (self, param1: int, param2: int)>
signature_ex(Example.method_b)
<Signature (self, param1: int, param2: int)>
obj = Example.method_b
params = L(signature_ex(obj, eval_str=True).parameters.keys())
params
(#3) ['self','param1','param2']
DocmentTbl(Example.method_b)
DocmentTbl(Example.method_a)