Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
ndsampler
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
computer-vision
ndsampler
Merge requests
!43
Start branch for dev/0.7.9
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Start branch for dev/0.7.9
dev/0.7.9
into
main
Overview
0
Commits
10
Pipelines
7
Changes
18
Merged
Jon Crall
requested to merge
dev/0.7.9
into
main
1 year ago
Overview
0
Commits
10
Pipelines
7
Changes
18
Expand
auto created MR
0
0
Merge request reports
Compare
main
version 7
90f68633
10 months ago
version 6
957cdf01
10 months ago
version 5
e02705ad
10 months ago
version 4
96405dbc
11 months ago
version 3
fc40b456
1 year ago
version 2
9333e81a
1 year ago
version 1
9333e81a
1 year ago
main (base)
and
latest version
latest version
01c2e4c8
10 commits,
10 months ago
version 7
90f68633
9 commits,
10 months ago
version 6
957cdf01
8 commits,
10 months ago
version 5
e02705ad
7 commits,
10 months ago
version 4
96405dbc
3 commits,
11 months ago
version 3
fc40b456
2 commits,
1 year ago
version 2
9333e81a
1 commit,
1 year ago
version 1
9333e81a
1 commit,
1 year ago
18 files
+
553
−
231
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
18
Search (e.g. *.vue) (Ctrl+P)
dev/bench/bench_rtree_vs_quadtree.py
0 → 100644
+
239
−
0
Options
"""
Notes on spatial index structures
https://stackoverflow.com/questions/41946007/efficient-and-well-explained-implementation-of-a-quadtree-for-2d-collision-det
https://github.com/Elan456/pyquadtree
https://informix-spatial-technology.blogspot.com/2012/01/comparison-on-b-tree-r-tree-quad-tree.html
TODO:
Look into CDAL: https://github.com/CGAL/cgal-swig-bindings/wiki/Package_wrappers_available
"""
import
kwimage
import
rtree
import
pyqtree
import
numpy
as
np
import
ubelt
as
ub
import
kwarray
try
:
from
line_profiler
import
profile
except
Exception
:
profile
=
ub
.
identity
class
RTreeWrapper
():
"""
Wrapper around pure python libspatialindex rtree implementation:
https://pypi.org/project/Rtree/
https://rtree.readthedocs.io/en/latest/tutorial.html#using-rtree-as-a-cheapo-spatial-database
https://libspatialindex.org/en/latest/
"""
def
__init__
(
self
,
width
,
height
):
self
.
width
=
width
self
.
height
=
height
self
.
_module
=
pyqtree
self
.
_tree
=
rtree
.
index
.
Index
(
bounds
=
[
0
,
0
,
width
,
height
])
self
.
aid_to_ltrb
=
{}
@profile
def
add_annotation
(
self
,
annot_id
,
ltrb_box
):
_tree
=
self
.
_tree
_tree
.
insert
(
annot_id
,
ltrb_box
,
obj
=
annot_id
)
self
.
aid_to_ltrb
[
annot_id
]
=
ltrb_box
@profile
def
query
(
self
,
ltrb_box
):
isect_aids
=
sorted
(
set
(
self
.
_tree
.
intersection
(
ltrb_box
)))
return
isect_aids
class
PyQTreeWrapper
():
"""
Wrapper around pure python QTree implementation:
https://pypi.org/project/Pyqtree/
"""
def
__init__
(
self
,
width
,
height
):
self
.
width
=
width
self
.
height
=
height
self
.
_module
=
pyqtree
self
.
_tree
=
pyqtree
.
Index
((
0
,
0
,
width
,
height
))
self
.
aid_to_ltrb
=
{}
@profile
def
add_annotation
(
self
,
annot_id
,
ltrb_box
):
self
.
_tree
.
insert
(
annot_id
,
ltrb_box
)
self
.
aid_to_ltrb
[
annot_id
]
=
ltrb_box
@profile
def
query
(
self
,
ltrb_box
):
isect_aids
=
sorted
(
set
(
self
.
_tree
.
intersect
(
ltrb_box
)))
return
isect_aids
class
MultiFrameTree
:
def
__init__
(
self
,
backend
):
if
backend
==
'
rtree
'
:
self
.
_cls
=
RTreeWrapper
elif
backend
==
'
pyqtree
'
:
self
.
_cls
=
PyQTreeWrapper
else
:
raise
KeyError
(
backend
)
self
.
image_id_to_tree
=
{}
def
add_image
(
self
,
image_id
,
width
,
height
):
tree
=
self
.
_cls
(
width
,
height
)
self
.
image_id_to_tree
[
image_id
]
=
tree
return
tree
def
__getitem__
(
self
,
image_id
):
tree
=
self
.
image_id_to_tree
[
image_id
]
return
tree
def
generate_demo_data
(
basis_item
):
"""
Generate a random-ish set of images with boxes and a set of query
boxes for each of those images.
"""
num_images
=
basis_item
[
'
num_images
'
]
=
basis_item
.
get
(
'
num_images
'
,
100
)
annots_per_image
=
basis_item
[
'
annots_per_image
'
]
=
basis_item
.
get
(
'
annots_per_image
'
,
100
)
window_scale
=
basis_item
[
'
window_scale
'
]
=
basis_item
.
get
(
'
window_scale
'
,
1
/
8
)
image_dim
=
basis_item
[
'
image_dim
'
]
=
basis_item
.
get
(
'
image_dim
'
,
4_000
)
width
=
image_dim
height
=
image_dim
image_to_info
=
{}
max_annot_id
=
0
for
image_id
in
range
(
num_images
):
boxes
=
kwimage
.
Boxes
.
random
(
annots_per_image
).
scale
((
width
,
height
)).
round
()
# Make boxes spatially smaller to simulate lots of tiny objects in a
# large image
boxes
=
boxes
.
scale
(
0.1
,
about
=
'
centroid
'
)
first_annot_id
=
max_annot_id
+
1
last_annot_id
=
first_annot_id
+
annots_per_image
-
1
annot_ids
=
np
.
arange
(
first_annot_id
,
last_annot_id
+
1
)
query_slices
=
list
(
kwarray
.
SlidingWindow
(
shape
=
(
width
,
height
),
window
=
(
int
(
width
*
window_scale
),
int
(
height
*
window_scale
)),
keepbound
=
True
,
allow_overshoot
=
True
))
query_boxes
=
kwimage
.
Boxes
.
concatenate
([
kwimage
.
Boxes
.
from_slice
(
s
)
for
s
in
query_slices
])
image_to_info
[
image_id
]
=
{
'
width
'
:
width
,
'
height
'
:
height
,
'
boxes
'
:
boxes
,
'
annot_ids
'
:
annot_ids
,
'
query_boxes
'
:
query_boxes
,
'
num_images
'
:
num_images
,
'
width
'
:
width
,
'
height
'
:
height
,
'
annots_per_image
'
:
annots_per_image
,
}
max_annot_id
=
last_annot_id
return
image_to_info
def
run_tests
(
image_to_info
):
backends
=
{}
backends
[
'
rtree
'
]
=
MultiFrameTree
(
backend
=
'
rtree
'
)
backends
[
'
pyqtree
'
]
=
MultiFrameTree
(
backend
=
'
pyqtree
'
)
measures
=
[]
real_results
=
{}
for
backend_name
,
backend
in
backends
.
items
():
with
ub
.
Timer
()
as
build_timer
:
for
image_id
,
info
in
image_to_info
.
items
():
tree
=
backend
.
add_image
(
image_id
,
info
[
'
width
'
],
info
[
'
height
'
])
boxes
=
info
[
'
boxes
'
].
to_ltrb
()
annot_ids
=
info
[
'
annot_ids
'
]
for
annot_id
,
ltrb_box
in
zip
(
annot_ids
,
boxes
.
data
):
tree
.
add_annotation
(
annot_id
,
ltrb_box
)
with
ub
.
Timer
()
as
query_timer
:
impl_results
=
[]
for
image_id
,
info
in
image_to_info
.
items
():
boxes
=
info
[
'
query_boxes
'
].
to_ltrb
()
tree
=
backend
[
image_id
]
for
query_box
in
boxes
:
found
=
tree
.
query
(
ltrb_box
)
impl_results
.
append
(
found
)
real_results
[
backend_name
]
=
impl_results
measure
=
{}
measure
[
'
build_time
'
]
=
build_timer
.
elapsed
measure
[
'
query_time
'
]
=
query_timer
.
elapsed
measure
[
'
backend_name
'
]
=
backend_name
measures
.
append
(
measure
)
assert
real_results
[
'
rtree
'
]
==
real_results
[
'
pyqtree
'
]
return
measures
def
main
():
basis
=
list
(
ub
.
named_product
({
'
num_images
'
:
[
1
,
100
,
500
,
1_000
,
# 5_000, 10_000, 25_000, 50_000
],
'
annots_per_image
'
:
[
100
,
1000
],
'
window_scale
'
:
[
1
/
8
,
1
/
16
],
}))
all_measures
=
[]
for
basis_item
in
ub
.
ProgIter
(
basis
,
verbose
=
3
,
desc
=
'
Measure Times
'
):
print
(
f
'
basis_item =
{
ub
.
urepr
(
basis_item
,
nl
=
1
)
}
'
)
image_to_info
=
generate_demo_data
(
basis_item
)
measures
=
run_tests
(
image_to_info
)
for
m
in
measures
:
m
.
update
(
basis_item
)
print
(
f
'
measures =
{
ub
.
urepr
(
measures
,
nl
=
1
)
}
'
)
all_measures
.
extend
(
measures
)
import
pandas
as
pd
import
kwplot
sns
=
kwplot
.
autosns
()
df
=
pd
.
DataFrame
(
all_measures
)
ax
=
kwplot
.
figure
(
fnum
=
1
,
doclf
=
True
,
pnum
=
(
1
,
2
,
1
)).
gca
()
sns
.
lineplot
(
data
=
df
,
x
=
'
num_images
'
,
y
=
'
build_time
'
,
hue
=
'
backend_name
'
,
style
=
'
annots_per_image
'
,
ax
=
ax
)
ax
.
set_title
(
'
Build Time
'
)
ax
=
kwplot
.
figure
(
fnum
=
1
,
docla
=
True
,
pnum
=
(
1
,
2
,
2
)).
gca
()
sns
.
lineplot
(
data
=
df
,
x
=
'
num_images
'
,
y
=
'
query_time
'
,
hue
=
'
backend_name
'
,
# style='annots_per_image',
style
=
'
window_scale
'
,
ax
=
ax
)
ax
.
set_title
(
'
Query Time
'
)
kwplot
.
show_if_requested
()
if
__name__
==
'
__main__
'
:
"""
CommandLine:
python ~/code/ndsampler/dev/bench/bench_rtree_vs_quadtree.py --show
LINE_PROFILE=1 python ~/code/ndsampler/dev/bench/bench_rtree_vs_quadtree.py
"""
main
()
Loading