///|
/// An image declared by the ground-truth dataset.
pub struct Image {
id : Int
width : Int
height : Int
} derive(Debug, Eq)
///|
pub extend Image with Debug::{to_repr}
///|
pub extend Image with Eq::{equal, not_equal}
///|
pub fn Image::new(id : Int, width : Int, height : Int) -> Image raise EvalError {
if width <= 0 || height <= 0 {
raise InvalidInput("image width and height must be positive")
}
{ id, width, height, }
}
///|
pub fn Image::id(self : Image) -> Int {
self.id
}
///|
pub fn Image::width(self : Image) -> Int {
self.width
}
///|
pub fn Image::height(self : Image) -> Int {
self.height
}
///|
pub struct Category {
id : Int
name : String
} derive(Debug, Eq)
///|
pub extend Category with Debug::{to_repr}
///|
pub extend Category with Eq::{equal, not_equal}
///|
pub fn Category::new(id : Int, name : String) -> Category raise EvalError {
if name.is_empty() {
raise InvalidInput("category name must be nonempty")
}
{ id, name, }
}
///|
pub fn Category::id(self : Category) -> Int {
self.id
}
///|
pub fn Category::name(self : Category) -> String {
self.name
}
///|
/// A validated COCO-style ground-truth object.
pub struct GroundTruth {
id : Int64
image_id : Int
category_id : Int
bbox : Box
area : Double
iscrowd : Bool
ignore : Bool
} derive(Debug, Eq)
///|
pub extend GroundTruth with Debug::{to_repr}
///|
pub extend GroundTruth with Eq::{equal, not_equal}
///|
pub fn GroundTruth::new(
id : Int64,
image_id : Int,
category_id : Int,
bbox : Box,
area~ : Double,
iscrowd? : Bool = false,
ignore? : Bool = false,
) -> GroundTruth raise EvalError {
if !finite(area) || area < 0.0 {
raise InvalidInput("ground-truth area must be finite and nonnegative")
}
{ id, image_id, category_id, bbox, area, iscrowd, ignore, }
}
///|
pub fn GroundTruth::id(self : GroundTruth) -> Int64 {
self.id
}
///|
pub fn GroundTruth::image_id(self : GroundTruth) -> Int {
self.image_id
}
///|
pub fn GroundTruth::category_id(self : GroundTruth) -> Int {
self.category_id
}
///|
pub fn GroundTruth::bbox(self : GroundTruth) -> Box {
self.bbox
}
///|
pub fn GroundTruth::area(self : GroundTruth) -> Double {
self.area
}
///|
pub fn GroundTruth::iscrowd(self : GroundTruth) -> Bool {
self.iscrowd
}
///|
pub fn GroundTruth::ignore(self : GroundTruth) -> Bool {
self.ignore
}
///|
/// A scored detector output. `id` is stable within one evaluation.
pub struct Detection {
id : Int
image_id : Int
category_id : Int
bbox : Box
score : Double
} derive(Debug, Eq)
///|
pub extend Detection with Debug::{to_repr}
///|
pub extend Detection with Eq::{equal, not_equal}
///|
pub fn Detection::new(
id : Int,
image_id : Int,
category_id : Int,
bbox : Box,
score : Double,
) -> Detection raise EvalError {
if !finite(score) {
raise InvalidInput("detection score must be finite")
}
{ id, image_id, category_id, bbox, score, }
}
///|
pub fn Detection::id(self : Detection) -> Int {
self.id
}
///|
pub fn Detection::image_id(self : Detection) -> Int {
self.image_id
}
///|
pub fn Detection::category_id(self : Detection) -> Int {
self.category_id
}
///|
pub fn Detection::bbox(self : Detection) -> Box {
self.bbox
}
///|
pub fn Detection::score(self : Detection) -> Double {
self.score
}
///|
/// A reusable, immutable evaluation input.
pub struct Dataset {
images : Array[Image]
categories : Array[Category]
truths : Array[GroundTruth]
}
///|
pub fn Dataset::new(
images : Array[Image],
categories : Array[Category],
truths : Array[GroundTruth],
) -> Dataset raise EvalError {
let image_ids : Map[Int, Bool] = Map([])
let category_ids : Map[Int, Bool] = Map([])
let truth_ids : Map[Int64, Bool] = Map([])
for image in images {
if image_ids.contains(image.id) {
raise InvalidInput("duplicate image id \{image.id}")
}
image_ids[image.id] = true
}
for category in categories {
if category_ids.contains(category.id) {
raise InvalidInput("duplicate category id \{category.id}")
}
category_ids[category.id] = true
}
for truth in truths {
if truth_ids.contains(truth.id) {
raise InvalidInput("duplicate ground-truth id \{truth.id}")
}
if !image_ids.contains(truth.image_id) ||
!category_ids.contains(truth.category_id) {
raise InvalidInput(
"ground-truth \{truth.id} references unknown image or category",
)
}
truth_ids[truth.id] = true
}
{
images: images.copy(),
categories: categories.copy(),
truths: truths.copy(),
}
}
///|
pub fn Dataset::images(self : Dataset) -> Array[Image] {
self.images.copy()
}
///|
pub fn Dataset::categories(self : Dataset) -> Array[Category] {
self.categories.copy()
}
///|
pub fn Dataset::truths(self : Dataset) -> Array[GroundTruth] {
self.truths.copy()
}