diff --git a/labs/lab2/lab2.ipynb b/labs/lab2/lab2.ipynb index e521abc..90bf9bd 100644 --- a/labs/lab2/lab2.ipynb +++ b/labs/lab2/lab2.ipynb @@ -60,7 +60,7 @@ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets\n", - "from nptyping import NDArray\n", + "from nptyping import NDArray, Shape\n", "from typing import Any, Tuple, List, Optional\n", "\n", "# Import Racecar library\n", @@ -107,7 +107,7 @@ "\n", " \n", "def draw_circle(\n", - " color_image: NDArray[(Any, Any, 3), np.uint8],\n", + " color_image: NDArray[Shape[\"*, *, 3\"], np.uint8],\n", " center: Tuple[int, int],\n", " color: Tuple[int, int, int] = (0, 255, 255),\n", " radius: int = 6,\n", @@ -324,7 +324,7 @@ "outputs": [], "source": [ "def get_mask(\n", - " image: NDArray[(Any, Any, 3), np.uint8],\n", + " image: NDArray[Shape[\"*, *, 3\"], np.uint8],\n", " hsv_lower: Tuple[int, int, int],\n", " hsv_upper: Tuple[int, int, int]\n", ") -> NDArray[Any, Any]:\n", @@ -931,7 +931,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -945,7 +945,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.10.2" } }, "nbformat": 4, diff --git a/labs/lab3/lab3.ipynb b/labs/lab3/lab3.ipynb index 28d03ac..79f7800 100644 --- a/labs/lab3/lab3.ipynb +++ b/labs/lab3/lab3.ipynb @@ -57,7 +57,7 @@ "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets\n", "import statistics\n", - "from nptyping import NDArray\n", + "from nptyping import NDArray, Shape\n", "from typing import Any, Tuple, List, Optional\n", "\n", "# Import Racecar library\n", @@ -80,7 +80,7 @@ "outputs": [], "source": [ "def show_depth_image(\n", - " depth_image: NDArray[(Any, Any), np.float32],\n", + " depth_image: NDArray[Shape[\"*, *\"], np.float32],\n", " max_depth: int = 400,\n", " points: List[Tuple[int, int]] = []\n", ") -> None:\n", @@ -111,10 +111,10 @@ "\n", "\n", "def add_noise(\n", - " depth_image: NDArray[(Any, Any), np.float32],\n", + " depth_image: NDArray[Shape[\"*, *\"], np.float32],\n", " error_percent = 0.1,\n", " null_percent: float = 0.005\n", - ") -> NDArray[(Any, Any), np.float32]:\n", + ") -> NDArray[Shape[\"*, *\"], np.float32]:\n", " \"\"\"\n", " Adds noise to a depth image.\n", " \n", @@ -359,7 +359,7 @@ "outputs": [], "source": [ "def get_depth_image_center_distance(\n", - " depth_image: NDArray[(Any, Any), np.float32], \n", + " depth_image: NDArray[Shape[\"*, *\"], np.float32], \n", " kernel_size: int\n", ") -> float:\n", " \"\"\"\n", @@ -445,7 +445,7 @@ "outputs": [], "source": [ "def get_closest_pixel(\n", - " depth_image: NDArray[(Any, Any), np.float32],\n", + " depth_image: NDArray[Shape[\"*, *\"], np.float32],\n", " kernel_size: int = 5\n", ") -> Tuple[int, int]:\n", " \"\"\"\n", @@ -530,7 +530,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -544,7 +544,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.10.2" } }, "nbformat": 4, diff --git a/library/camera.py b/library/camera.py index 8764b4d..ad93c69 100644 --- a/library/camera.py +++ b/library/camera.py @@ -10,6 +10,7 @@ import copy import numpy as np from nptyping import NDArray +from nptyping import Shape class Camera(abc.ABC): @@ -24,7 +25,7 @@ class Camera(abc.ABC): # Maximum range of the depth camera (in cm) _MAX_RANGE = 1200 - def get_color_image(self) -> NDArray[(480, 640, 3), np.uint8]: + def get_color_image(self) -> NDArray[Shape["480, 640, 3"], np.uint8]: """ Returns a deep copy of the current color image captured by the camera. @@ -53,7 +54,7 @@ def get_color_image(self) -> NDArray[(480, 640, 3), np.uint8]: return copy.deepcopy(self.get_color_image_no_copy()) @abc.abstractmethod - def get_color_image_no_copy(self) -> NDArray[(480, 640, 3), np.uint8]: + def get_color_image_no_copy(self) -> NDArray[Shape["480, 640, 3"], np.uint8]: """ Returns a direct reference to the color image captured by the camera. @@ -94,7 +95,7 @@ def get_color_image_no_copy(self) -> NDArray[(480, 640, 3), np.uint8]: pass @abc.abstractmethod - def get_color_image_async(self) -> NDArray[(480, 640, 3), np.uint8]: + def get_color_image_async(self) -> NDArray[Shape["480, 640, 3"], np.uint8]: """ Returns the current color image without the car in "go" mode. @@ -122,7 +123,7 @@ def get_color_image_async(self) -> NDArray[(480, 640, 3), np.uint8]: pass @abc.abstractmethod - def get_depth_image(self) -> NDArray[(480, 640), np.float32]: + def get_depth_image(self) -> NDArray[Shape["480, 640"], np.float32]: """ Returns the current depth image captured by the camera. @@ -141,7 +142,7 @@ def get_depth_image(self) -> NDArray[(480, 640), np.float32]: pass @abc.abstractmethod - def get_depth_image_async(self) -> NDArray[(480, 640), np.float32]: + def get_depth_image_async(self) -> NDArray[Shape["480, 640"], np.float32]: """ Returns the current depth image without the car in "go" mode. diff --git a/library/display.py b/library/display.py index 8fa13b8..18ba894 100644 --- a/library/display.py +++ b/library/display.py @@ -11,6 +11,7 @@ import math from typing import List, Tuple, Any from nptyping import NDArray +from nptyping import Shape import racecar_utils as rc_utils @@ -68,7 +69,7 @@ def show_color_image(self, image: NDArray) -> None: def show_depth_image( self, - image: NDArray[(Any, Any), np.float32], + image: NDArray[Shape["*,*"], np.float32], max_depth: int = 1000, points: List[Tuple[int, int]] = [], ) -> None: diff --git a/library/lidar.py b/library/lidar.py index a7be08c..49e77d0 100644 --- a/library/lidar.py +++ b/library/lidar.py @@ -9,6 +9,7 @@ import abc import numpy as np from nptyping import NDArray +from nptyping import Shape class Lidar(abc.ABC): @@ -20,7 +21,7 @@ class Lidar(abc.ABC): _NUM_SAMPLES: int = 720 @abc.abstractmethod - def get_samples(self) -> NDArray[720, np.float32]: + def get_samples(self) -> NDArray[Shape["720"], np.float32]: """ Returns the current LIDAR scan as an array of distance measurements. @@ -42,7 +43,7 @@ def get_samples(self) -> NDArray[720, np.float32]: pass @abc.abstractmethod - def get_samples_async(self) -> NDArray[720, np.float32]: + def get_samples_async(self) -> NDArray[Shape["720"], np.float32]: """ Returns the current LIDAR scan without the car in "go" mode. diff --git a/library/physics.py b/library/physics.py index 5ad59cb..88740c5 100644 --- a/library/physics.py +++ b/library/physics.py @@ -9,6 +9,7 @@ import abc import numpy as np from nptyping import NDArray +from nptyping import Shape class Physics(abc.ABC): @@ -17,7 +18,7 @@ class Physics(abc.ABC): """ @abc.abstractmethod - def get_linear_acceleration(self) -> NDArray[3, np.float32]: + def get_linear_acceleration(self) -> NDArray[Shape["3"], np.float32]: """ Returns a 3D vector containing the car's linear acceleration. @@ -42,7 +43,7 @@ def get_linear_acceleration(self) -> NDArray[3, np.float32]: pass @abc.abstractmethod - def get_angular_velocity(self) -> NDArray[3, np.float32]: + def get_angular_velocity(self) -> NDArray[Shape["3"], np.float32]: """ Returns a 3D vector containing the car's angular velocity. diff --git a/library/racecar_utils.py b/library/racecar_utils.py index a81f9d1..2092cc2 100644 --- a/library/racecar_utils.py +++ b/library/racecar_utils.py @@ -10,6 +10,7 @@ import numpy as np from typing import * from nptyping import NDArray +from nptyping import Shape from enum import Enum, IntEnum @@ -187,10 +188,10 @@ def remap_range( def crop( - image: NDArray[(Any, ...), Any], + image: NDArray[Shape["*, ..."], Any], top_left_inclusive: Tuple[float, float], bottom_right_exclusive: Tuple[float, float], -) -> NDArray[(Any, ...), Any]: +) -> NDArray[Shape["*, ..."], Any]: """ Crops an image to a rectangle based on the specified pixel points. @@ -241,8 +242,8 @@ def crop( def stack_images_horizontal( - image_0: NDArray[(Any, ...), Any], image_1: NDArray[(Any, ...), Any] -) -> NDArray[(Any, ...), Any]: + image_0: NDArray[Shape["*, ..."], Any], image_1: NDArray[Shape["*, ..."], Any] +) -> NDArray[Shape["*, ..."], Any]: """ Stack two images horizontally. @@ -274,8 +275,8 @@ def stack_images_horizontal( def stack_images_vertical( - image_0: NDArray[(Any, ...), Any], image_1: NDArray[(Any, ...), Any] -) -> NDArray[(Any, ...), Any]: + image_0: NDArray[Shape["*, ..."], Any], image_1: NDArray[Shape["*, ..."], Any] +) -> NDArray[Shape["*, ..."], Any]: """ Stack two images vertically. @@ -335,7 +336,7 @@ class ColorBGR(Enum): def find_contours( - color_image: NDArray[(Any, Any, 3), np.uint8], + color_image: NDArray[Shape["*, *, 3"], np.uint8], hsv_lower: Tuple[int, int, int], hsv_upper: Tuple[int, int, int], ) -> List[NDArray]: @@ -447,7 +448,7 @@ def get_largest_contour( def draw_contour( - color_image: NDArray[(Any, Any, 3), np.uint8], + color_image: NDArray[Shape["Any, Any, 3"], np.uint8], contour: NDArray, color: Tuple[int, int, int] = ColorBGR.green.value, ) -> None: @@ -483,7 +484,7 @@ def draw_contour( def draw_circle( - color_image: NDArray[(Any, Any, 3), np.uint8], + color_image: NDArray[Shape["Any, Any, 3"], np.uint8], center: Tuple[int, int], color: Tuple[int, int, int] = ColorBGR.yellow.value, radius: int = 6, @@ -600,7 +601,7 @@ def get_contour_area(contour: NDArray) -> float: def get_depth_image_center_distance( - depth_image: NDArray[(Any, Any), np.float32], kernel_size: int = 5 + depth_image: NDArray[Shape["*, *"], np.float32], kernel_size: int = 5 ) -> float: """ Finds the distance of the center object in a depth image. @@ -639,7 +640,7 @@ def get_depth_image_center_distance( def get_pixel_average_distance( - depth_image: NDArray[(Any, Any), np.float32], + depth_image: NDArray[Shape["*, *"], np.float32], pix_coord: Tuple[int, int], kernel_size: int = 5, ) -> float: @@ -711,7 +712,7 @@ def get_pixel_average_distance( def get_closest_pixel( - depth_image: NDArray[(Any, Any), np.float32], kernel_size: int = 5 + depth_image: NDArray[Shape["*, *"], np.float32], kernel_size: int = 5 ) -> Tuple[int, int]: """ Finds the closest pixel in a depth image. @@ -764,8 +765,8 @@ def get_closest_pixel( def colormap_depth_image( - depth_image: NDArray[(Any, Any), np.float32], max_depth: int = 1000, -) -> NDArray[(Any, Any, 3), np.uint8]: + depth_image: NDArray[Shape["*, *"], np.float32], max_depth: int = 1000, +) -> NDArray[Shape["*, *, 3"], np.uint8]: """ Converts a depth image to a colored image representing depth. @@ -967,7 +968,7 @@ class ARMarker: """ def __init__( - self, marker_id: int, marker_corners: NDArray[(4, 2), np.int32] + self, marker_id: int, marker_corners: NDArray[Shape["4, 2"], np.int32] ) -> None: """ Creates an object representing an AR marker. @@ -1007,7 +1008,7 @@ def __init__( def detect_colors( self, - color_image: NDArray[(Any, Any), np.float32], + color_image: NDArray[Shape["Any, Any"], np.float32], potential_colors: List[Tuple[Tuple[int, int, int], Tuple[int, int, int], str]], ) -> None: """ @@ -1068,7 +1069,7 @@ def get_id(self) -> int: """ return self.__id - def get_corners(self) -> NDArray[(4, 2), np.int32]: + def get_corners(self) -> NDArray[Shape["4, 2"], np.int32]: """ Returns the (row, col) coordinates of the four corners of the marker. @@ -1078,7 +1079,7 @@ def get_corners(self) -> NDArray[(4, 2), np.int32]: """ return self.__corners - def get_corners_aruco_format(self) -> NDArray[(1, 4, 2), np.float32]: + def get_corners_aruco_format(self) -> NDArray[Shape["1, 4, 2"], np.float32]: """ Returns the corners of the AR marker formatted as needed by the ArUco library. """ @@ -1113,7 +1114,7 @@ def __str__(self) -> str: def get_ar_markers( - color_image: NDArray[(Any, Any, 3), np.uint8], + color_image: NDArray[Shape["*, *, 3"], np.uint8], potential_colors: List[ Tuple[Tuple[int, int, int], Tuple[int, int, int], str] ] = None, @@ -1167,10 +1168,10 @@ def get_ar_markers( def draw_ar_markers( - color_image: NDArray[(Any, Any, 3), np.uint8], + color_image: NDArray[Shape["*, *, 3"], np.uint8], markers: List[ARMarker], color: Tuple[int, int, int] = ColorBGR.green.value, -) -> NDArray[(Any, Any, 3), np.uint8]: +) -> NDArray[Shape["*, *, 3"], np.uint8]: """ Draws annotations on the AR markers in a image. diff --git a/library/simulation/camera_sim.py b/library/simulation/camera_sim.py index afb627c..7ebd82f 100644 --- a/library/simulation/camera_sim.py +++ b/library/simulation/camera_sim.py @@ -2,6 +2,7 @@ import numpy as np import cv2 as cv from nptyping import NDArray +from nptyping import Shape from camera import Camera @@ -9,39 +10,39 @@ class CameraSim(Camera): def __init__(self, racecar) -> None: self.__racecar = racecar - self.__color_image: NDArray[(480, 640, 3), np.uint8] = None + self.__color_image: NDArray[Shape["480, 640, 3"], np.uint8] = None self.__is_color_image_current: bool = False - self.__depth_image: NDArray[(480, 640), np.float32] = None + self.__depth_image: NDArray[Shape["480, 640"], np.float32] = None self.__is_depth_image_current: bool = False self._MAX_DEPTH_WIDTH: int = self._WIDTH // 8 self._MAX_DEPTH_HEIGHT: int = self._HEIGHT // 8 - def get_color_image_no_copy(self) -> NDArray[(480, 640, 3), np.uint8]: + def get_color_image_no_copy(self) -> NDArray[Shape["480, 640, 3"], np.uint8]: if not self.__is_color_image_current: self.__color_image = self.__request_color_image(False) self.__is_color_image_current = True return self.__color_image - def get_color_image_async(self) -> NDArray[(480, 640, 3), np.uint8]: + def get_color_image_async(self) -> NDArray[Shape["480, 640, 3"], np.uint8]: return self.__request_color_image(True) - def get_depth_image(self) -> NDArray[(480, 640), np.float32]: + def get_depth_image(self) -> NDArray[Shape["480, 640"], np.float32]: if not self.__is_depth_image_current: self.__depth_image = self.__request_depth_image(False) self.__is_depth_image_current = False return self.__depth_image - def get_depth_image_async(self) -> NDArray[(480, 640), np.float32]: + def get_depth_image_async(self) -> NDArray[Shape["480, 640"], np.float32]: return self.__request_depth_image(True) def __update(self) -> None: self.__is_color_image_current = False self.__is_depth_image_current = False - def __request_color_image(self, isAsync: bool) -> NDArray[(480, 640), np.uint8]: + def __request_color_image(self, isAsync: bool) -> NDArray[Shape["480, 640"], np.uint8]: # Ask for a the current color image self.__racecar._RacecarSim__send_header( self.__racecar.Header.camera_get_color_image, isAsync @@ -57,7 +58,7 @@ def __request_color_image(self, isAsync: bool) -> NDArray[(480, 640), np.uint8]: color_image = cv.cvtColor(color_image, cv.COLOR_RGB2BGR) return color_image - def __request_depth_image(self, isAsync: bool) -> NDArray[(480, 640), np.float32]: + def __request_depth_image(self, isAsync: bool) -> NDArray[Shape["480, 640"], np.float32]: self.__racecar._RacecarSim__send_header( self.__racecar.Header.camera_get_depth_image, isAsync ) diff --git a/library/simulation/lidar_sim.py b/library/simulation/lidar_sim.py index 398fecf..fa1bc68 100644 --- a/library/simulation/lidar_sim.py +++ b/library/simulation/lidar_sim.py @@ -2,6 +2,7 @@ import struct import numpy as np from nptyping import NDArray +from nptyping import Shape from lidar import Lidar @@ -12,7 +13,7 @@ def __init__(self, racecar) -> None: self.__ranges: NDArray[720, np.float32] self.__is_current: bool = False - def get_samples(self) -> NDArray[720, np.float32]: + def get_samples(self) -> NDArray[Shape["720"], np.float32]: if not self.__is_current: self.__racecar._RacecarSim__send_header( self.__racecar.Header.lidar_get_samples @@ -24,7 +25,7 @@ def get_samples(self) -> NDArray[720, np.float32]: self.__is_current = True return self.__ranges - def get_samples_async(self) -> NDArray[720, np.float32]: + def get_samples_async(self) -> NDArray[Shape["720"], np.float32]: self.__racecar._RacecarSim__send_header( self.__racecar.Header.lidar_get_samples, True ) diff --git a/library/simulation/physics_sim.py b/library/simulation/physics_sim.py index 6dfe710..3da0b02 100644 --- a/library/simulation/physics_sim.py +++ b/library/simulation/physics_sim.py @@ -2,6 +2,7 @@ import struct import numpy as np from nptyping import NDArray +from nptyping import Shape from physics import Physics @@ -9,14 +10,14 @@ class PhysicsSim(Physics): def __init__(self, racecar) -> None: self.__racecar = racecar - def get_linear_acceleration(self) -> NDArray[3, np.float32]: + def get_linear_acceleration(self) -> NDArray[Shape["3"], np.float32]: self.__racecar._RacecarSim__send_header( self.__racecar.Header.physics_get_linear_acceleration ) values = struct.unpack("fff", self.__racecar._RacecarSim__receive_data(12)) return np.array(values) - def get_angular_velocity(self) -> NDArray[3, np.float32]: + def get_angular_velocity(self) -> NDArray[Shape["3"], np.float32]: self.__racecar._RacecarSim__send_header( self.__racecar.Header.physics_get_angular_velocity )