Skip to content

Commit

Permalink
Implemented Base.isapprox for object annotations and ImageAnnotation
Browse files Browse the repository at this point in the history
  • Loading branch information
stemann committed Sep 10, 2023
1 parent 432900c commit fc36b37
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/bounding_box_annotation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ function Base.:(==)(a::BoundingBoxAnnotation, b::BoundingBoxAnnotation)
return a.rect == b.rect && a.annotation == b.annotation
end

function Base.isapprox(a::BoundingBoxAnnotation, b::BoundingBoxAnnotation; kwargs...)
return isapprox(a.rect.origin, b.rect.origin; kwargs...) &&
isapprox(a.rect.widths, b.rect.widths; kwargs...) &&
isapprox(a.annotation, b.annotation; kwargs...)
end

# Accessors

get_bottom_right(annotation::BoundingBoxAnnotation) = annotation.rect.origin + annotation.rect.widths
Expand Down
13 changes: 13 additions & 0 deletions src/image_annotation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ function Base.:(==)(a::ImageAnnotation, b::ImageAnnotation)
return a.label == b.label && a.confidence == b.confidence && a.annotator_name == b.annotator_name
end

function Base.isapprox(a::ImageAnnotation{L}, b::ImageAnnotation{L}; kwargs...) where {L}
label_isapprox = L <: AbstractFloat ? isapprox(a.label, b.label; kwargs...) : a.label == b.label
a_confidence, b_confidence = a.confidence, b.confidence
a_annotator_name, b_annotator_name = a.annotator_name, b.annotator_name
conf_isapprox =
(isnothing(a_confidence) && isnothing(b_confidence)) ||
(!isnothing(a_confidence) && !isnothing(b_confidence) && isapprox(a_confidence, b_confidence; kwargs...))
annotator_isapprox =
isnothing(a_annotator_name) && isnothing(b_annotator_name) ||
(!isnothing(a_annotator_name) && !isnothing(b_annotator_name) && a_annotator_name == b_annotator_name)
return label_isapprox && conf_isapprox && annotator_isapprox
end

get_label(annotation::ImageAnnotation) = annotation.label
get_confidence(annotation::ImageAnnotation) = annotation.confidence
get_annotator_name(annotation::ImageAnnotation) = annotation.annotator_name
21 changes: 21 additions & 0 deletions src/oriented_bounding_box_annotation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,27 @@ function Base.:(==)(a::OrientedBoundingBoxAnnotation, b::OrientedBoundingBoxAnno
a.annotation == b.annotation
end

function Base.isapprox(
a::OrientedBoundingBoxAnnotation{L, T},
b::OrientedBoundingBoxAnnotation{L, T};
atol::Real = zero(T),
rtol::Real = atol > 0 ? zero(T) : eps(T),
linear_atol::Real = atol,
linear_rtol::Real = rtol,
angular_atol::Real = atol,
angular_rtol::Real = rtol,
orientation_symmetry::Bool = false,
kwargs...,
) where {L, T}
a_orientation = orientation_symmetry ? mod(a.orientation, π) : a.orientation
b_orientation = orientation_symmetry ? mod(b.orientation, π) : b.orientation
return isapprox(a.center, b.center; atol = linear_atol, rtol = linear_rtol, kwargs...) &&
isapprox(a.width, b.width; atol = linear_atol, rtol = linear_rtol, kwargs...) &&
isapprox(a.height, b.height; atol = linear_atol, rtol = linear_rtol, kwargs...) &&
isapprox(a_orientation, b_orientation; atol = angular_atol, rtol = angular_rtol, kwargs...) &&
isapprox(a.annotation, b.annotation; atol = atol, rtol = rtol, kwargs...)
end

# Accessors

get_width(annotation::OrientedBoundingBoxAnnotation) = annotation.width
Expand Down
4 changes: 4 additions & 0 deletions src/polygon_annotation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ function Base.:(==)(a::PolygonAnnotation, b::PolygonAnnotation)
return a.vertices == b.vertices && a.annotation == b.annotation
end

function Base.isapprox(a::PolygonAnnotation, b::PolygonAnnotation; kwargs...)
return isapprox(a.vertices, b.vertices; kwargs...) && isapprox(a.annotation, b.annotation; kwargs...)
end

# Accessors

get_vertices(annotation::PolygonAnnotation)::Vector{Point2} = annotation.vertices
Expand Down
22 changes: 22 additions & 0 deletions test/bounding_box_annotation_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ using Test
@test BoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, "car") != BoundingBoxAnnotation(Point2(1.0, 3.0), 3.0, 4.0, "car")
end

@testset "Base.isapprox" begin
linear_atol = 1e-1
approx(v, eps = 1e-2) = v + linear_atol - eps
napprox(v, eps = 1e-2) = v + linear_atol + eps
a = BoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, "car")

b = BoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, approx(4.0), "car")
c = BoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, napprox(4.0), "car")
@test a b atol = linear_atol
@test a c atol = linear_atol

b = BoundingBoxAnnotation(Point2(1.0, 2.0), approx(3.0), 4.0, "car")
c = BoundingBoxAnnotation(Point2(1.0, 2.0), napprox(3.0), 4.0, "car")
@test a b atol = linear_atol
@test a c atol = linear_atol

b = BoundingBoxAnnotation(Point2(1.0, approx(2.0)), 3.0, 4.0, "car")
c = BoundingBoxAnnotation(Point2(1.0, napprox(2.0)), 3.0, 4.0, "car")
@test a b atol = linear_atol
@test a c atol = linear_atol
end

@testset "get_centroid" begin
annotation = BoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, "car")
@test get_centroid(annotation) == Point2(2.5, 4.0)
Expand Down
29 changes: 29 additions & 0 deletions test/image_annotation_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,33 @@ using Test
@test isless(f, g)
end
end

@testset "Base.isapprox" begin
for TLabel in [Int, Float64, String]
a_label = ImageAnnotations.Dummies.create_label(TLabel)
if TLabel <: AbstractFloat
@testset "Annotations of $TLabel isapprox if label isapprox" begin
label_atol = eps(TLabel)
b_label = a_label + label_atol - eps(TLabel)
c_label = a_label + label_atol + eps(TLabel)
@assert isapprox(a_label, b_label; atol = label_atol)
@assert !isapprox(a_label, c_label; atol = label_atol)

a = ImageAnnotation(a_label)
b = ImageAnnotation(b_label)
c = ImageAnnotation(c_label)
@test a b atol = label_atol
@test a c atol = label_atol
end
else
@testset "Annotations of $TLabel isapprox if label isequal" begin
label_atol = 0
b_label = ImageAnnotations.Dummies.create_label(TLabel)
a = ImageAnnotation(a_label)
b = ImageAnnotation(b_label)
@test a b atol = label_atol
end
end
end
end
end
35 changes: 35 additions & 0 deletions test/oriented_bounding_box_annotation_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,41 @@ using Test
OrientedBoundingBoxAnnotation(Point2(1.0, 3.0), 3.0, 4.0, pi / 2, "car")
end

@testset "Base.isapprox" begin
linear_atol = 1e-1
approx(v, atol = linear_atol, eps = 1e-2) = v + atol - eps
napprox(v, atol = linear_atol, eps = 1e-2) = v + atol + eps
a = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, pi / 2, "car")

b = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, approx(pi / 2, pi / 64, pi / 128), "car")
c = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, napprox(pi / 2, pi / 64, pi / 128), "car")
d = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, pi / 2 - 2pi, "car")
e = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, pi / 2 - pi, "car")
f = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, pi / 2 + pi, "car")
g = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, 4.0, pi / 2 + 2pi, "car")
@test a b atol = pi / 64
@test a c atol = pi / 64
@test a d orientation_symmetry = true
@test a e orientation_symmetry = true
@test a f orientation_symmetry = true
@test a g orientation_symmetry = true

b = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, approx(4.0), pi / 2, "car")
c = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), 3.0, napprox(4.0), pi / 2, "car")
@test a b atol = linear_atol
@test a c atol = linear_atol

b = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), approx(3.0), 4.0, pi / 2, "car")
c = OrientedBoundingBoxAnnotation(Point2(1.0, 2.0), napprox(3.0), 4.0, pi / 2, "car")
@test a b atol = linear_atol
@test a c atol = linear_atol

b = OrientedBoundingBoxAnnotation(Point2(1.0, approx(2.0)), 3.0, 4.0, pi / 2, "car")
c = OrientedBoundingBoxAnnotation(Point2(1.0, napprox(2.0)), 3.0, 4.0, pi / 2, "car")
@test a b atol = linear_atol
@test a c atol = linear_atol
end

@testset "get_bounding_box" begin
annotation = OrientedBoundingBoxAnnotation(Point2(3.0, 3.0), 4.0, 2.0, pi / 2, "car")
expected_rect = Rect2(Point2(2.0, 1.0), 2.0, 4.0)
Expand Down
12 changes: 12 additions & 0 deletions test/polygon_annotation_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ using Test
PolygonAnnotation([Point2(2.0, 2.0), Point2(4.0, 2.0), Point2(3.0, 4.0)], "car")
end

@testset "Base.isapprox" begin
linear_atol = 1e-1
approx(v, eps = 1e-2) = v + linear_atol - eps
napprox(v, eps = 1e-2) = v + linear_atol + eps
a = PolygonAnnotation([Point2(2.0, 2.0), Point2(4.0, 2.0), Point2(3.0, 3.0)], "car")

b = PolygonAnnotation([Point2(2.0, 2.0), Point2(4.0, 2.0), Point2(3.0, approx(3.0))], "car")
c = PolygonAnnotation([Point2(2.0, 2.0), Point2(4.0, 2.0), Point2(3.0, napprox(3.0))], "car")
@test a b atol = linear_atol
@test a c atol = linear_atol
end

@testset "get_bounding_box" begin
annotation = PolygonAnnotation([Point2(2.0, 2.0), Point2(4.0, 2.0), Point2(3.0, 3.0)], "car")
rect = get_bounding_box(annotation)
Expand Down

0 comments on commit fc36b37

Please sign in to comment.