2026-01-28 06:16:04 +00:00

733 lines
29 KiB
Python

"""Classes to be used by the different processing functions.
These classes are wrappers around their corresponding structs defined in
c_interface/include/model_res.h. They will hold results after the appropriate C processing
function is called.
"""
import ctypes
import string
from typing import List, Mapping, NewType, Optional, TypeVar, Union
import numpy as np
import numpy.typing as npt
BOXES_MAX_NUM = 80
CLASSIFIER_MAX_NUM = 1000
FR_FEATURE_MAP_SIZE = 256
KEYPOINT_POINTS = 11
LANDMARK_POINTS = 5
MAX_KEYPOINTS = 100
MAX_ONET_POINTS = 100
MAX_YOLO_FACE_LANDMARK_CNT = 8
OCR_MAX_NUM = 20
SEG_WIDTH = 80
SEG_HEIGHT = 60
class AgeGenderResult(ctypes.Structure):
"""Age and gender result.
Attributes:
age: An integer indicating the age of the detected person.
gender: An integer indicating the gender of detected person (0: female, 1: male).
"""
_fields_ = [("age", ctypes.c_uint32),
("ismale", ctypes.c_uint32)]
def __init__(self, age: int = 0, ismale: int = 0):
self.age = age
self.ismale = ismale
super().__init__()
def __repr__(self):
gender = "male" if self.ismale else "female"
return ("---------------------------- Age Gender Result ----------------------------\n"
f"Age: {self.age}\nGender: {gender}\n")
class BoundingBox(ctypes.Structure):
"""Box that outlines the detected object in the image.
Attributes:
x1: A float x coordinate of the top left corner.
y1: A float y coordinate of the top left corner.
x2: A float x coordinate of the bottom right corner.
y2: A float y coordinate of the bottom right corner.
score: A float indicating the probability score of the box.
class_num: An integer indicating the class with the highest score.
"""
_fields_ = [("x1", ctypes.c_float),
("y1", ctypes.c_float),
("x2", ctypes.c_float),
("y2", ctypes.c_float),
("score", ctypes.c_float),
("class_num", ctypes.c_int32)]
def __init__(self, x1: float = 0, y1: float = 0, x2: float = 0, y2: float = 0,
score: float = 0, class_num: int = 0):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.score = score
self.class_num = class_num
super().__init__()
def __repr__(self):
box = f"Box (x1, y1, x2, y2): ({self.x1}, {self.y1}, {self.x2}, {self.y2})"
return ("------------------------------ Bounding Box -------------------------------\n"
f"{box}\nScore: {self.score}\nClass number: {self.class_num}\n")
def to_np(self, box_type: str = "xyxy", to_round: bool = False) -> npt.NDArray:
"""Returns a NumPy array of the 6 data values.
Args:
box_type: String indicating the format to return the box coordinates. "xyxy" or "xywh".
to_round: If True, box coordinate values will be rounded to the nearest integer.
If box_type is "xywh", rounding will be done first before subtraction.
Returns:
A NumPy array of length 6 with either of the following formats, depending on the
provided box_type:
"xyxy": [x1, y1, x2, y2, score, class_num]
"xywh": [x1, y1, w, h, score, class_num]
Raises:
ValueError: If box_type is not supported
"""
box = np.array([self.x1, self.y1, self.x2, self.y2, self.score, self.class_num])
if to_round:
box[:4] = np.round(box[:4])
if box_type == "xyxy":
return box
elif box_type == "xywh":
box[2] -= box[0]
box[3] -= box[1]
return box
else:
raise ValueError(f"to_np (BoundingBox): box_type must be one of "
f"['xyxy', 'xywh'], not {box_type}")
class BoundingBoxLandmark(ctypes.Structure):
"""Box that outlines the detected object in the image, including landmark data.
Attributes:
x1: A float x coordinate of the top left corner.
y1: A float y coordinate of the top left corner.
x2: A float x coordinate of the bottom right corner.
y2: A float y coordinate of the bottom right corner.
score: A float indicating the probability score of the box.
class_num: An integer indicating the class with the highest score.
lm: A list of floats indicating the landmark coordinates.
"""
_fields_ = [("x1", ctypes.c_float),
("y1", ctypes.c_float),
("x2", ctypes.c_float),
("y2", ctypes.c_float),
("score", ctypes.c_float),
("class_num", ctypes.c_int32),
("lm", ctypes.c_float * MAX_YOLO_FACE_LANDMARK_CNT)]
def __init__(self, x1: float = 0, y1: float = 0, x2: float = 0, y2: float = 0,
score: float = 0, class_num: int = 0, lm: Optional[float] = None):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.score = score
self.class_num = class_num
if lm is not None:
self.lm = (ctypes.c_float * MAX_YOLO_FACE_LANDMARK_CNT)(*lm)
super().__init__()
def __repr__(self):
box = f"Box (x1, y1, x2, y2): ({self.x1}, {self.y1}, {self.x2}, {self.y2})"
lm_repr = "Landmarks:\n"
for (index, landmark) in enumerate(self.lm):
if index % 2: # y
lm_repr += f"{landmark})\n"
else: # x
lm_repr += f"LM[{index // 2}] (x, y): ({landmark}, "
return ("------------------------- Bounding Box + Landmark -------------------------\n"
f"{box}\nScore: {self.score}\nClass number: {self.class_num}\n{lm_repr}\n")
def box_to_np(self, box_type: str = "xyxy", to_round: bool = False) -> npt.NDArray:
"""Returns a NumPy array of the bounding box data.
Args:
box_type: String indicating the format to return the box coordinates. "xyxy" or "xywh".
to_round: If True, box coordinate values will be rounded to the nearest integer.
If box_type is "xywh", rounding will be done first before subtraction.
Returns:
A NumPy array of length 6 with either of the following formats, depending on the
provided box_type:
"xyxy": [x1, y1, x2, y2, score, class_num]
"xywh": [x1, y1, w, h, score, class_num]
Raises:
ValueError: If box_type is not supported
"""
box = np.array([self.x1, self.y1, self.x2, self.y2, self.score, self.class_num])
if to_round:
box[:4] = np.round(box[:4])
if box_type == "xyxy":
return box
elif box_type == "xywh":
box[2] -= box[0]
box[3] -= box[1]
return box
else:
raise ValueError(f"to_np (BoundingBox): box_type must be one of "
f"['xyxy', 'xywh'], not {box_type}")
def lm_to_np(self) -> npt.NDArray:
"""Returns a NumPy array of the landmark data."""
return np.array(self.lm)
class BoundingBoxLandmarkPlus(ctypes.Structure):
"""Box that outlines the detected object in the image, including landmarks and top 2 scores.
Attributes:
x1: A float x coordinate of the top left corner.
y1: A float y coordinate of the top left corner.
x2: A float x coordinate of the bottom right corner.
y2: A float y coordinate of the bottom right corner.
score: A float indicating the probability score of the box.
class_num: An integer indicating the class with the highest score.
score_next: A float indicating the probability score of the box.
class_num_next: An integer indicating the class with the highest score.
lm: A list of floats indicating the landmark coordinates.
"""
_fields_ = [("x1", ctypes.c_float),
("y1", ctypes.c_float),
("x2", ctypes.c_float),
("y2", ctypes.c_float),
("score", ctypes.c_float),
("class_num", ctypes.c_int32),
("score_next", ctypes.c_float),
("class_num_next", ctypes.c_int32),
("lm", ctypes.c_float * MAX_YOLO_FACE_LANDMARK_CNT)]
def __init__(self, x1: float = 0, y1: float = 0, x2: float = 0, y2: float = 0,
score: float = 0, class_num: int = 0, score_next: float = 0,
class_num_next: int = 0, lm: Optional[float] = None):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.score = score
self.class_num = class_num
self.score_next = score_next
self.class_num_next = class_num_next
if lm is not None:
self.lm = (ctypes.c_float * MAX_YOLO_FACE_LANDMARK_CNT)(*lm)
super().__init__()
def __repr__(self):
box = f"Box (x1, y1, x2, y2): ({self.x1}, {self.y1}, {self.x2}, {self.y2})"
lm_repr = "Landmarks:\n"
for (index, landmark) in enumerate(self.lm):
if index % 2: # y
lm_repr += f"{landmark})\n"
else: # x
lm_repr += f"LM[{index // 2}] (x, y): ({landmark}, "
return ("------------------------- Bounding Box + Landmark -------------------------\n"
f"{box}\nScore: {self.score}\nClass number: {self.class_num}\n2nd score: "
f"{self.score_next}\n2nd class number: {self.class_num_next}\n{lm_repr}\n")
def box_to_np(self, box_type: str = "xyxy", to_round: bool = False,
second_best: bool = False) -> npt.NDArray:
"""Returns a NumPy array of the bounding box data.
Args:
box_type: String indicating the format to return the box coordinates. "xyxy" or "xywh".
to_round: If True, box coordinate values will be rounded to the nearest integer.
If box_type is "xywh", rounding will be done first before subtraction.
second_best: If True, box will also have the second highest score and class number.
Returns:
A NumPy array of length 6 with either of the following formats, depending on the
provided box_type:
"xyxy": [x1, y1, x2, y2, score, class_num]
"xywh": [x1, y1, w, h, score, class_num]
If second_best is set, each box will have two additional values appended to the end:
second highest score and corresponding class number.
Raises:
ValueError: If box_type is not supported
"""
if second_best:
box = np.array([self.x1, self.y1, self.x2, self.y2, self.score, self.class_num,
self.score_next, self.class_num_next])
else:
box = np.array([self.x1, self.y1, self.x2, self.y2, self.score, self.class_num])
if to_round:
box[:4] = np.round(box[:4])
if box_type == "xyxy":
return box
elif box_type == "xywh":
box[2] -= box[0]
box[3] -= box[1]
return box
else:
raise ValueError(f"to_np (BoundingBox): box_type must be one of "
f"['xyxy', 'xywh'], not {box_type}")
def lm_to_np(self) -> npt.NDArray:
"""Returns a NumPy array of the landmark data."""
return np.array(self.lm)
class ClassifierResult(ctypes.Structure):
"""Classifier result.
Attributes:
score: A float array holding scores for each class index
"""
_fields_ = [("score", ctypes.c_float * CLASSIFIER_MAX_NUM)]
def __init__(self, score: Optional[List[float]] = None):
if score is not None:
self.score = (ctypes.c_float * CLASSIFIER_MAX_NUM)(*score)
super().__init__()
def __repr__(self):
first_ten = "Displaying first 10 scores:\n"
for index, score in enumerate(self.score[:10]):
first_ten += f"Score[{index}]: {score}\n"
return ("---------------------------- Classifier Result ----------------------------\n"
f"{first_ten}\n")
class FaceOccludeResult(ctypes.Structure):
"""Face pose result.
Attributes:
yaw: A float indicating yaw value.
pitch: A float indicating pitch value.
roll: A float indicating roll value.
occ: A float indicating occlusion value.
"""
_fields_ = [("yaw", ctypes.c_float),
("pitch", ctypes.c_float),
("roll", ctypes.c_float),
("occ", ctypes.c_float)]
def __init__(self, yaw: float = 0, pitch: float = 0, roll: float = 0, occ: float = 0):
self.yaw = yaw
self.pitch = pitch
self.roll = roll
self.occ = occ
super().__init__()
def __repr__(self):
return ("--------------------------- Face Occlude Result ---------------------------\n"
f"Yaw: {self.yaw}\nPitch: {self.pitch}\nRoll: {self.roll}\nOcc: {self.occ}")
class FRResult(ctypes.Structure):
"""Face recognition result.
Attributes:
feature_map: A list of floats indicating the feature map.
"""
_fields_ = [("feature_map", ctypes.c_float * FR_FEATURE_MAP_SIZE)]
def __init__(self, feature_map: Optional[List[float]] = None):
if feature_map is not None:
self.feature_map = (ctypes.c_float * FR_FEATURE_MAP_SIZE)(*feature_map)
super().__init__()
def __repr__(self):
first_ten = "Displaying first 10 feature map values:\n"
for index, value in enumerate(self.feature_map[:10]):
first_ten += f"FR[{index}]: {value}\n"
return ("-------------------------------- FR Result --------------------------------\n"
f"{first_ten}\n")
class LandmarkPoint(ctypes.Structure):
"""Landmark point in integer format.
Attributes:
x: An integer indicating the x coordinate.
y: An integer indicating the y coordinate.
"""
_fields_ = [("x", ctypes.c_uint32),
("y", ctypes.c_uint32)]
def __init__(self, x: int = 0, y: int = 0):
self.x = x
self.y = y
super().__init__()
def __repr__(self):
return f"Landmark point (x, y): ({self.x}, {self.y})"
class LandmarkPointFloat(ctypes.Structure):
"""Landmark point in floating point format.
Attributes:
x: A float indicating the x coordinate.
y: A float indicating the y coordinate.
"""
_fields_ = [("x", ctypes.c_float),
("y", ctypes.c_float)]
def __init__(self, x: float = 0, y: float = 0):
self.x = x
self.y = y
super().__init__()
def __repr__(self):
return f"Landmark point (x, y): ({self.x}, {self.y})"
class LandmarkResult(ctypes.Structure):
"""Landmark result for variable number of landmarks.
Attributes:
marks: List of LandmarkPoint instances.
score: A float indicating the probability score.
blur: A float indicating the blur.
"""
_fields_ = [("marks", LandmarkPoint * MAX_ONET_POINTS),
("score", ctypes.c_float),
("blur", ctypes.c_float)]
def __init__(self, marks: Optional[List[LandmarkPoint]] = None,
score: float = 0, blur: float = 0):
if marks is not None:
self.marks = (LandmarkPoint * MAX_ONET_POINTS)(*marks)
self.score = score
self.blur = blur
super().__init__()
def __repr__(self):
landmarks = "Landmarks:\n"
for index, point in enumerate(self.marks):
landmarks += f"#{index} {point}\n"
return ("----------------------------- Landmark Result -----------------------------\n"
f"{landmarks}\nScore: {self.score}\nBlur: {self.blur}")
class LandmarkResult5p(ctypes.Structure):
"""Landmark result for 5 landmark points.
Attributes:
marks: List of LandmarkPoint instances.
score: A float indicating the probability score.
blur: A float indicating the blur.
class_num: An integer indicating the class number with the highest score.
"""
_fields_ = [("marks", LandmarkPoint * LANDMARK_POINTS),
("score", ctypes.c_float),
("blur", ctypes.c_float),
("class_num", ctypes.c_int32)]
def __init__(self, marks: Optional[List[LandmarkPoint]] = None,
score: float = 0, blur: float = 0, class_num: int = 0):
if marks is not None:
self.marks = (LandmarkPoint * LANDMARK_POINTS)(*marks)
self.score = score
self.blur = blur
self.class_num = class_num
super().__init__()
def __repr__(self):
landmarks = "Landmarks:\n"
for index, point in enumerate(self.marks):
landmarks += f"#{index} {point}\n"
return ("----------------------------- Landmark Result -----------------------------\n"
f"{landmarks}\nScore: {self.score}\nBlur: {self.blur}\nClass number: "
f"{self.class_num}")
class Keypoint(ctypes.Structure):
"""Keypoint.
Attributes:
x: A float indicating the x coordinate.
y: A float indicating the y coordinate.
"""
_fields_ = [("x", ctypes.c_float),
("y", ctypes.c_float)]
def __init__(self, x: float = 0, y: float = 0):
self.x = x
self.y = y
super().__init__()
def __repr__(self):
return f"Keypoint point (x, y): ({self.x}, {self.y})"
class KeyPointResult(ctypes.Structure):
"""Keypoint result.
Attributes:
point_count: An integer indicating the number of points found.
points: List of Keypoint instances.
scores: A list of floats indicating the probability scores for each Keypoint.
"""
_fields_ = [("point_count", ctypes.c_uint32),
("points", Keypoint * MAX_KEYPOINTS),
("scores", ctypes.c_float * MAX_KEYPOINTS)]
def __init__(self, point_count: int = 0, points: Optional[List[Keypoint]] = None,
scores: Optional[List[float]] = None):
self.point_count = point_count
if points is not None:
self.points = (Keypoint * MAX_KEYPOINTS)(*points)
if scores is not None:
self.scores = (ctypes.c_float * MAX_KEYPOINTS)(*scores)
super().__init__()
def __repr__(self):
keypoint = "Keypoints:\n"
for index, (point, score) in enumerate(zip(self.points[:self.point_count],
self.scores[:self.point_count])):
keypoint += f"#{index} {point}, Score: {score}\n"
return ("----------------------------- Keypoint Result -----------------------------\n"
f"{keypoint}")
class OnetPlusResult(ctypes.Structure):
"""ONET plus result.
Attributes:
marks: List of LandmarkPointFloat instances.
scores: A list of floats indicating the probability scores for each landmark.
"""
_fields_ = [("marks", LandmarkPointFloat * LANDMARK_POINTS),
("scores", ctypes.c_float * LANDMARK_POINTS)]
def __init__(self, marks: Optional[List[LandmarkPointFloat]] = None,
scores: Optional[List[float]] = None):
if marks is not None:
self.marks = (LandmarkPointFloat * LANDMARK_POINTS)(*marks)
if scores is not None:
self.scores = (ctypes.c_float * LANDMARK_POINTS)(*scores)
super().__init__()
def __repr__(self):
landmarks = "Landmarks:\n"
for index, point in enumerate(self.marks):
landmarks += (f"#{index} {point}; score: {self.scores[index]}\n")
return ("----------------------------- ONET Plus Result ----------------------------\n"
f"{landmarks}")
class OCRResult(ctypes.Structure):
"""Licenseplate OCR result.
Attributes:
char_count: An integer indicating the number of characters found.
char_boxes: Sequence of BoundingBox instances found in an image.
valid: An integer indicating if the plate is valid.
hyphen: An integer indicating the position the hyphen comes after.
"""
_fields_ = [("char_count", ctypes.c_uint32),
("char_boxes", BoundingBox * OCR_MAX_NUM),
("valid", ctypes.c_uint8),
("hyphen", ctypes.c_uint8)]
char_map = string.digits + string.ascii_uppercase
def __init__(self, char_count: int = 0, char_boxes: Optional[BoundingBox] = None,
valid: int = 0, hyphen: int = 0):
self.char_count = char_count
if char_boxes is not None:
self.char_boxes = (BoundingBox * OCR_MAX_NUM)(*char_boxes)
self.valid = valid
self.hyphen = hyphen
super().__init__()
def __repr__(self):
box_repr = ""
for index, box in enumerate(self.char_boxes[:self.char_count]):
box_repr += f"\nBox #{index}:\n{box}\n"
return ("------------------------------- OCR Result --------------------------------\n"
f"Plate: {self.get_plate()}\nBox_count: {self.char_count}\n{box_repr}\n")
def get_plate(self, input_map: Optional[Mapping[str, str]] = None):
"""Returns the plate value from the detected boxes.
Args:
input_map: Mapping from string representing the class number to a string
representing the actual character value.
Returns:
A string representing the values on the licenseplate.
"""
if not self.valid:
return ""
if input_map is None:
char_map = self.char_map
else:
char_map = list(input_map.values())
chars = [char_map[box.class_num] for box in self.char_boxes[:self.char_count]]
if self.hyphen:
# hyphen is the character after which it should be placed
chars = [*chars[:self.hyphen + 1], "-", *chars[self.hyphen + 1:]]
return "".join(chars)
class PersonHeadResult(ctypes.Structure):
"""Results of person bounding boxes mapped to head bounding boxes.
Attributes:
num_persons: An integer indicating number of total people.
num_heads: An integer indicating number of matching heads.
person_boxes: List of all person BoundingBox instances.
head_boxes: List of all matching head BoundingBox instances.
"""
_fields_ = [("num_persons", ctypes.c_uint32),
("num_heads", ctypes.c_uint32),
("person_boxes", BoundingBox * BOXES_MAX_NUM),
("head_boxes", BoundingBox * BOXES_MAX_NUM)]
def __init__(self, num_persons: int = 0, num_heads: int = 0,
person_boxes: Optional[List[BoundingBox]] = None,
head_boxes: Optional[List[BoundingBox]] = None):
self.num_persons = num_persons
self.num_heads = num_heads
if person_boxes is not None:
self.person_boxes = (BoundingBox * BOXES_MAX_NUM)(*person_boxes)
if head_boxes is not None:
self.head_boxes = (BoundingBox * BOXES_MAX_NUM)(*head_boxes)
super().__init__()
def __repr__(self):
box_repr = ""
for index, (person_box, head_box) in enumerate(zip(self.person_boxes[:self.num_persons],
self.head_boxes[:self.num_heads])):
box_repr += f"\nPerson #{index}:\n{person_box}\nCorresponding head:\n{head_box}\n"
return ("--------------------------- Person Head Result ----------------------------\n"
f"Person count: {self.num_persons}\nHead count: {self.num_heads}\n{box_repr}\n")
class SegResult(ctypes.Structure):
"""Semantic segmentation result.
Attributes:
seg_class_result: List of integers indicating the class number for each image pixel.
"""
_fields_ = [("seg_class_result", ctypes.c_uint32 * (SEG_WIDTH * SEG_HEIGHT))]
def __init__(self, seg_class_result: Optional[List[int]] = None):
if seg_class_result is not None:
self.seg_class_result = (ctypes.c_uint32 * (SEG_WIDTH * SEG_HEIGHT))(*seg_class_result)
super().__init__()
def __repr__(self):
first_ten = "Displaying first 10 pixels:\n"
for index, value in enumerate(self.seg_class_result[:10]):
first_ten += f"seg[{index}]: {value}\n"
return ("--------------------------- Segmentation Result ---------------------------\n"
f"{first_ten}")
def to_np(self) -> npt.NDArray[np.uint32]:
"""Returns a NumPy array of the class numbers for each pixel."""
classes = np.asarray(self.seg_class_result, dtype=np.uint32)
return np.reshape(classes, (SEG_HEIGHT, SEG_WIDTH))
class UpperbodyKeypointResult(ctypes.Structure):
"""Upperbody keypoint result.
Attributes:
marks: List of Keypoint instances.
"""
_fields_ = [("marks", Keypoint * KEYPOINT_POINTS)]
def __init__(self, marks: Optional[List[Keypoint]] = None):
if marks is not None:
self.marks = (Keypoint * KEYPOINT_POINTS)(*marks)
super().__init__()
def __repr__(self):
keypoint = "Keypoints:\n"
for index, point in enumerate(self.marks):
keypoint += f"#{index} {point}\n"
return ("----------------------------- Keypoint Result -----------------------------\n"
f"{keypoint}")
class YoloResult(ctypes.Structure):
"""Results of all bounding boxes found in an image.
Attributes:
class_count: An integer indicating total possible classes.
box_count: An integer indicating number of found boxes.
boxes: List of BoundingBox instances found in an image.
"""
_fields_ = [("class_count", ctypes.c_uint32),
("box_count", ctypes.c_uint32),
("boxes", BoundingBox * BOXES_MAX_NUM)]
def __init__(self, class_count: int = 0, box_count: int = 0,
boxes: Optional[List[BoundingBox]] = None):
self.class_count = class_count
self.box_count = box_count
if boxes is not None:
self.boxes = (BoundingBox * BOXES_MAX_NUM)(*boxes)
super().__init__()
def __repr__(self):
box_repr = ""
for index, box in enumerate(self.boxes[:self.box_count]):
box_repr += f"\nBox #{index}:\n{box}\n"
return ("------------------------------- Yolo Result -------------------------------\n"
f"Class count: {self.class_count}\nBox_count: {self.box_count}\n{box_repr}\n")
class YoloLandmarkResult(ctypes.Structure):
"""Results of all bounding boxes (including landmark data) found in an image.
Attributes:
class_count: An integer indicating total possible classes.
box_count: An integer indicating number of found boxes.
boxes: List of BoundingBoxLandmark instances found in an image.
"""
_fields_ = [("class_count", ctypes.c_uint32),
("box_count", ctypes.c_uint32),
("boxes", BoundingBoxLandmark * BOXES_MAX_NUM)]
def __init__(self, class_count: int = 0, box_count: int = 0,
boxes: Optional[List[BoundingBoxLandmark]] = None):
self.class_count = class_count
self.box_count = box_count
if boxes is not None:
self.boxes = (BoundingBoxLandmark * BOXES_MAX_NUM)(*boxes)
super().__init__()
def __repr__(self):
box_repr = ""
for index, box in enumerate(self.boxes[:self.box_count]):
box_repr += f"\nBox #{index}:\n{box}\n"
return ("------------------------------- Yolo Result -------------------------------\n"
f"Class count: {self.class_count}\nBox_count: {self.box_count}\n{box_repr}\n")
class YoloxLandmarkResult(ctypes.Structure):
"""Results of all bounding boxes (including landmark data) found in an image.
Attributes:
class_count: An integer indicating total possible classes.
box_count: An integer indicating number of found boxes.
boxes: List of BoundingBoxLandmarkPlus instances found in an image.
"""
_fields_ = [("class_count", ctypes.c_uint32),
("box_count", ctypes.c_uint32),
("boxes", BoundingBoxLandmarkPlus * BOXES_MAX_NUM)]
def __init__(self, class_count: int = 0, box_count: int = 0,
boxes: Optional[List[BoundingBoxLandmarkPlus]] = None):
self.class_count = class_count
self.box_count = box_count
if boxes is not None:
self.boxes = (BoundingBoxLandmarkPlus * BOXES_MAX_NUM)(*boxes)
super().__init__()
def __repr__(self):
box_repr = ""
for index, box in enumerate(self.boxes[:self.box_count]):
box_repr += f"\nBox #{index}:\n{box}\n"
return ("------------------------------- Yolo Result -------------------------------\n"
f"Class count: {self.class_count}\nBox_count: {self.box_count}\n{box_repr}\n")
Det = NewType("Det", List[List[Union[float, int]]])
ResultClass = TypeVar("ResultClass", AgeGenderResult, ClassifierResult, FaceOccludeResult,
FRResult, LandmarkResult, LandmarkResult5p, KeyPointResult, OnetPlusResult,
OCRResult, PersonHeadResult, SegResult, UpperbodyKeypointResult,
YoloResult, YoloLandmarkResult, YoloxLandmarkResult)