mapreader 1.3.6__tar.gz → 1.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mapreader-1.3.6 → mapreader-1.3.7}/PKG-INFO +1 -1
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/_version.py +3 -3
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/annotate/annotator.py +62 -18
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/classify/load_annotations.py +23 -2
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/PKG-INFO +1 -1
- {mapreader-1.3.6 → mapreader-1.3.7}/LICENSE +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/README.md +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/__main__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/annotate/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/annotate/utils.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/classify/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/classify/classifier.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/classify/custom_models.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/classify/datasets.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/data_structures.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/downloader.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/downloader_utils.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/sheet_downloader.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/tile_loading.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/download/tile_merging.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/load/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/load/geo_utils.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/load/images.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/load/loader.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/process/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/process/context_post_process.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/process/occlusion_analysis.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/process/process.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/spot_text/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/spot_text/deepsolo_runner.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/spot_text/dptext_detr_runner.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/spot_text/maptext_runner.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/spot_text/runner_base.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/utils/__init__.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/utils/compute_and_save_stats.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader/utils/slice_parallel.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/SOURCES.txt +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/dependency_links.txt +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/entry_points.txt +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/not-zip-safe +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/requires.txt +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/mapreader.egg-info/top_level.txt +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/setup.cfg +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/setup.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/tests/test_geo_pipeline.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/tests/test_import.py +0 -0
- {mapreader-1.3.6 → mapreader-1.3.7}/versioneer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mapreader
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.7
|
|
4
4
|
Summary: A computer vision pipeline for the semantic exploration of maps/images at scale
|
|
5
5
|
Home-page: https://github.com/Living-with-machines/MapReader
|
|
6
6
|
Download-URL: https://github.com/Living-with-machines/MapReader/archive/refs/heads/main.zip
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-08-
|
|
11
|
+
"date": "2024-08-12T15:00:36+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "1.3.
|
|
14
|
+
"full-revisionid": "6eec8310fe00efb31c03d0f4618dd7dd8a8ebd46",
|
|
15
|
+
"version": "1.3.7"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -55,6 +55,8 @@ class Annotator:
|
|
|
55
55
|
Name of the column in which labels are stored in patch DataFrame, by default "label"
|
|
56
56
|
show_context : bool, optional
|
|
57
57
|
Whether to show context when loading patches, by default False
|
|
58
|
+
border : bool, optional
|
|
59
|
+
Whether to add a border around the central patch when showing context, by default False
|
|
58
60
|
auto_save : bool, optional
|
|
59
61
|
Whether to automatically save annotations, by default True
|
|
60
62
|
delimiter : str, optional
|
|
@@ -108,6 +110,7 @@ class Annotator:
|
|
|
108
110
|
patch_paths_col: str = "image_path",
|
|
109
111
|
label_col: str = "label",
|
|
110
112
|
show_context: bool = False,
|
|
113
|
+
border: bool = False,
|
|
111
114
|
auto_save: bool = True,
|
|
112
115
|
delimiter: str = ",",
|
|
113
116
|
sortby: str | None = None,
|
|
@@ -255,6 +258,7 @@ class Annotator:
|
|
|
255
258
|
self.patch_paths_col = patch_paths_col
|
|
256
259
|
self.annotations_file = annotations_file
|
|
257
260
|
self.show_context = show_context
|
|
261
|
+
self.border = border
|
|
258
262
|
self.auto_save = auto_save
|
|
259
263
|
self.username = username
|
|
260
264
|
self.task_name = task_name
|
|
@@ -452,7 +456,7 @@ class Annotator:
|
|
|
452
456
|
|
|
453
457
|
self.navbox = widgets.VBox([widgets.HBox([prev_btn, next_btn])])
|
|
454
458
|
|
|
455
|
-
def
|
|
459
|
+
def _get_queue(
|
|
456
460
|
self, as_type: str | None = "list"
|
|
457
461
|
) -> list[int] | (pd.Index | pd.Series):
|
|
458
462
|
"""
|
|
@@ -520,7 +524,7 @@ class Annotator:
|
|
|
520
524
|
return indices
|
|
521
525
|
return queue_df
|
|
522
526
|
|
|
523
|
-
def
|
|
527
|
+
def _get_context(self):
|
|
524
528
|
"""
|
|
525
529
|
Provides the surrounding context for the patch to be annotated.
|
|
526
530
|
|
|
@@ -531,15 +535,21 @@ class Annotator:
|
|
|
531
535
|
context.
|
|
532
536
|
"""
|
|
533
537
|
|
|
534
|
-
def
|
|
538
|
+
def get_square(image_path, dim=True, border=False):
|
|
535
539
|
# Resize the image
|
|
536
540
|
im = Image.open(image_path)
|
|
537
541
|
|
|
538
542
|
# Dim the image
|
|
539
|
-
if dim in [True,
|
|
543
|
+
if dim in ["True", True]:
|
|
540
544
|
im_array = np.array(im)
|
|
541
545
|
im_array = 256 - (256 - im_array) * 0.4 # lighten image
|
|
542
546
|
im = Image.fromarray(im_array.astype(np.uint8))
|
|
547
|
+
|
|
548
|
+
if border in ["True", True] and self.border:
|
|
549
|
+
w, h = im.size
|
|
550
|
+
im = ImageOps.expand(im, border=2, fill="red")
|
|
551
|
+
im = im.resize((w, h))
|
|
552
|
+
|
|
543
553
|
return im
|
|
544
554
|
|
|
545
555
|
def get_empty_square(patch_size: tuple[int, int]):
|
|
@@ -593,7 +603,10 @@ class Annotator:
|
|
|
593
603
|
|
|
594
604
|
# derive ids from items
|
|
595
605
|
ids = [x.index[0] if len(x.index) == 1 else None for x in items]
|
|
596
|
-
|
|
606
|
+
# list of booleans, True if not the current patch, False if the current patch
|
|
607
|
+
# used for dimming the surrounding patches and adding a border to the current patch
|
|
608
|
+
dim_bools = [x != ix for x in ids]
|
|
609
|
+
border_bools = [x == ix for x in ids]
|
|
597
610
|
|
|
598
611
|
# derive images from items
|
|
599
612
|
image_paths = [
|
|
@@ -601,14 +614,16 @@ class Annotator:
|
|
|
601
614
|
]
|
|
602
615
|
|
|
603
616
|
# zip them
|
|
604
|
-
image_list = list(zip(image_paths,
|
|
617
|
+
image_list = list(zip(image_paths, dim_bools, border_bools))
|
|
605
618
|
|
|
606
619
|
# split them into rows
|
|
607
620
|
per_row = len(deltas)
|
|
608
621
|
images = [
|
|
609
622
|
[
|
|
610
|
-
|
|
611
|
-
|
|
623
|
+
get_square(image_path, dim=dim, border=border)
|
|
624
|
+
if image_path
|
|
625
|
+
else get_empty_square((width, height))
|
|
626
|
+
for image_path, dim, border in lst
|
|
612
627
|
]
|
|
613
628
|
for lst in array_split(image_list, per_row)
|
|
614
629
|
]
|
|
@@ -641,6 +656,7 @@ class Annotator:
|
|
|
641
656
|
def annotate(
|
|
642
657
|
self,
|
|
643
658
|
show_context: bool | None = None,
|
|
659
|
+
border: bool | None = None,
|
|
644
660
|
sortby: str | None = None,
|
|
645
661
|
ascending: bool | None = None,
|
|
646
662
|
min_values: dict | None = None,
|
|
@@ -648,6 +664,7 @@ class Annotator:
|
|
|
648
664
|
surrounding: int | None = None,
|
|
649
665
|
resize_to: int | None = None,
|
|
650
666
|
max_size: int | None = None,
|
|
667
|
+
show_vals: list[str] | None = None,
|
|
651
668
|
) -> None:
|
|
652
669
|
"""Annotate at the patch-level of the current patch.
|
|
653
670
|
Renders the annotation interface for the first image.
|
|
@@ -657,6 +674,9 @@ class Annotator:
|
|
|
657
674
|
show_context : bool or None, optional
|
|
658
675
|
Whether or not to display the surrounding context for each image.
|
|
659
676
|
Default is None.
|
|
677
|
+
border : bool or None, optional
|
|
678
|
+
Whether or not to display a border around the image (when using `show_context`).
|
|
679
|
+
Default is None.
|
|
660
680
|
sortby : str or None, optional
|
|
661
681
|
Name of the column to use to sort the patch DataFrame, by default None.
|
|
662
682
|
Default sort order is ``ascending=True``. Pass ``ascending=False`` keyword argument to sort in descending order.
|
|
@@ -677,12 +697,18 @@ class Annotator:
|
|
|
677
697
|
max_size : int or None, optional
|
|
678
698
|
The size in pixels for the longest side to which constrain each
|
|
679
699
|
patch image. Default: 100.
|
|
700
|
+
resize_to : int or None, optional
|
|
701
|
+
The size in pixels for the longest side to which resize each patch image. Default: None.
|
|
702
|
+
show_vals : list[str] or None, optional
|
|
703
|
+
List of column names to show in the display. By default, None.
|
|
680
704
|
|
|
681
705
|
Notes
|
|
682
706
|
-----
|
|
683
707
|
This method is a wrapper for the
|
|
684
708
|
:meth:`~.annotate.annotator.Annotate._annotate` method.
|
|
685
709
|
"""
|
|
710
|
+
if border is not None:
|
|
711
|
+
self.border = border
|
|
686
712
|
if sortby is not None:
|
|
687
713
|
self._sortby = sortby
|
|
688
714
|
if ascending is not None:
|
|
@@ -693,8 +719,10 @@ class Annotator:
|
|
|
693
719
|
if max_values is not None:
|
|
694
720
|
self._max_values = max_values
|
|
695
721
|
|
|
722
|
+
self.show_vals = show_vals
|
|
723
|
+
|
|
696
724
|
# re-set up queue using new min/max values
|
|
697
|
-
self._queue = self.
|
|
725
|
+
self._queue = self._get_queue()
|
|
698
726
|
|
|
699
727
|
self._annotate(
|
|
700
728
|
show_context=show_context,
|
|
@@ -743,7 +771,7 @@ class Annotator:
|
|
|
743
771
|
self.max_size = max_size
|
|
744
772
|
|
|
745
773
|
# re-set up queue
|
|
746
|
-
self._queue = self.
|
|
774
|
+
self._queue = self._get_queue()
|
|
747
775
|
|
|
748
776
|
if self._filter_for is not None:
|
|
749
777
|
print(f"[INFO] Filtering for: {self._filter_for}")
|
|
@@ -767,7 +795,7 @@ class Annotator:
|
|
|
767
795
|
Previous index, current index, and path of the current image.
|
|
768
796
|
"""
|
|
769
797
|
if self.current_index == len(self._queue):
|
|
770
|
-
self.
|
|
798
|
+
self._render_complete()
|
|
771
799
|
return
|
|
772
800
|
|
|
773
801
|
self.previous_index = self.current_index
|
|
@@ -777,7 +805,7 @@ class Annotator:
|
|
|
777
805
|
|
|
778
806
|
img_path = self.patch_df.at[ix, self.patch_paths_col]
|
|
779
807
|
|
|
780
|
-
self.
|
|
808
|
+
self._render()
|
|
781
809
|
return self.previous_index, self.current_index, img_path
|
|
782
810
|
|
|
783
811
|
def _prev_example(self, *_) -> tuple[int, int, str]:
|
|
@@ -790,7 +818,7 @@ class Annotator:
|
|
|
790
818
|
Previous index, current index, and path of the current image.
|
|
791
819
|
"""
|
|
792
820
|
if self.current_index == len(self._queue):
|
|
793
|
-
self.
|
|
821
|
+
self._render_complete()
|
|
794
822
|
return
|
|
795
823
|
|
|
796
824
|
if self.current_index > 0:
|
|
@@ -801,10 +829,10 @@ class Annotator:
|
|
|
801
829
|
|
|
802
830
|
img_path = self.patch_df.at[ix, self.patch_paths_col]
|
|
803
831
|
|
|
804
|
-
self.
|
|
832
|
+
self._render()
|
|
805
833
|
return self.previous_index, self.current_index, img_path
|
|
806
834
|
|
|
807
|
-
def
|
|
835
|
+
def _render(self) -> None:
|
|
808
836
|
"""
|
|
809
837
|
Displays the image at the current index in the annotation interface.
|
|
810
838
|
|
|
@@ -817,7 +845,7 @@ class Annotator:
|
|
|
817
845
|
"""
|
|
818
846
|
# Check whether we have reached the end
|
|
819
847
|
if self.current_index >= len(self) - 1:
|
|
820
|
-
self.
|
|
848
|
+
self._render_complete()
|
|
821
849
|
return
|
|
822
850
|
|
|
823
851
|
ix = self._queue[self.current_index]
|
|
@@ -841,7 +869,7 @@ class Annotator:
|
|
|
841
869
|
clear_output(wait=True)
|
|
842
870
|
image = self.get_patch_image(ix)
|
|
843
871
|
if self.show_context:
|
|
844
|
-
context = self.
|
|
872
|
+
context = self._get_context()
|
|
845
873
|
self._context_image = context
|
|
846
874
|
display(context.convert("RGB"))
|
|
847
875
|
else:
|
|
@@ -852,6 +880,22 @@ class Annotator:
|
|
|
852
880
|
text = f'<p><a href="{url}" target="_blank">Click to see entire map.</a></p>'
|
|
853
881
|
add_ins += [widgets.HTML(text)]
|
|
854
882
|
|
|
883
|
+
if self.show_vals:
|
|
884
|
+
patch_info = []
|
|
885
|
+
for col in self.show_vals:
|
|
886
|
+
if col in self.patch_df.columns:
|
|
887
|
+
val = self.patch_df.at[ix, col]
|
|
888
|
+
if isinstance(val, float):
|
|
889
|
+
val = f"{val:.4g}"
|
|
890
|
+
patch_info.append(f"<b>{col}</b>: {val}")
|
|
891
|
+
add_ins += [
|
|
892
|
+
widgets.HTML(
|
|
893
|
+
'<p style="text-align: center">'
|
|
894
|
+
+ "<br>".join(patch_info)
|
|
895
|
+
+ "</p>"
|
|
896
|
+
)
|
|
897
|
+
]
|
|
898
|
+
|
|
855
899
|
value = self.current_index + 1 if self.current_index else 1
|
|
856
900
|
description = f"{value} / {len(self._queue)}"
|
|
857
901
|
add_ins += [
|
|
@@ -983,7 +1027,7 @@ class Annotator:
|
|
|
983
1027
|
_filter = ~self.patch_df[self.label_col].isna()
|
|
984
1028
|
return self.patch_df[_filter]
|
|
985
1029
|
|
|
986
|
-
def
|
|
1030
|
+
def _render_complete(self):
|
|
987
1031
|
"""
|
|
988
1032
|
Renders the completion message once all images have been annotated.
|
|
989
1033
|
|
|
@@ -25,6 +25,7 @@ class AnnotationsLoader:
|
|
|
25
25
|
|
|
26
26
|
def __init__(self):
|
|
27
27
|
self.annotations = pd.DataFrame()
|
|
28
|
+
self.labels_map = {}
|
|
28
29
|
self.reviewed = pd.DataFrame()
|
|
29
30
|
self.patch_paths_col = None
|
|
30
31
|
self.label_col = None
|
|
@@ -33,6 +34,7 @@ class AnnotationsLoader:
|
|
|
33
34
|
def load(
|
|
34
35
|
self,
|
|
35
36
|
annotations: str | pd.DataFrame,
|
|
37
|
+
labels_map: dict | None = None,
|
|
36
38
|
delimiter: str | None = ",",
|
|
37
39
|
images_dir: str | None = None,
|
|
38
40
|
remove_broken: bool | None = True,
|
|
@@ -52,6 +54,8 @@ class AnnotationsLoader:
|
|
|
52
54
|
annotations : Union[str, pd.DataFrame]
|
|
53
55
|
The annotations.
|
|
54
56
|
Can either be the path to a csv file or a pandas.DataFrame.
|
|
57
|
+
labels_map : Optional[dict], optional
|
|
58
|
+
A dictionary mapping labels to indices. If not provided, labels will be mapped to indices based on the order in which they appear in the annotations dataframe. By default None.
|
|
55
59
|
delimiter : Optional[str], optional
|
|
56
60
|
The delimiter to use when loading the csv file as a dataframe, by default ",".
|
|
57
61
|
images_dir : Optional[str], optional
|
|
@@ -132,8 +136,25 @@ class AnnotationsLoader:
|
|
|
132
136
|
|
|
133
137
|
self.unique_labels = self.annotations[self.label_col].unique().tolist()
|
|
134
138
|
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
# if labels_map is explicitly provided
|
|
140
|
+
if labels_map:
|
|
141
|
+
self.labels_map = dict(
|
|
142
|
+
sorted(labels_map.items())
|
|
143
|
+
) # sort labels_map by keys
|
|
144
|
+
if not set(self.unique_labels).issubset(set(labels_map.values())):
|
|
145
|
+
raise ValueError(
|
|
146
|
+
"[ERROR] There are label(s) in the annotations that are not in the labels map. Please check the labels_map."
|
|
147
|
+
)
|
|
148
|
+
# if inferring labels_map
|
|
149
|
+
else:
|
|
150
|
+
if append:
|
|
151
|
+
for label in self.unique_labels:
|
|
152
|
+
if label not in self.labels_map.values():
|
|
153
|
+
self.labels_map[len(self.labels_map)] = label
|
|
154
|
+
else:
|
|
155
|
+
# reset labels map
|
|
156
|
+
labels_map = {i: label for i, label in enumerate(self.unique_labels)}
|
|
157
|
+
self.labels_map = labels_map
|
|
137
158
|
|
|
138
159
|
self.annotations["label_index"] = self.annotations[self.label_col].apply(
|
|
139
160
|
self._get_label_index
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mapreader
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.7
|
|
4
4
|
Summary: A computer vision pipeline for the semantic exploration of maps/images at scale
|
|
5
5
|
Home-page: https://github.com/Living-with-machines/MapReader
|
|
6
6
|
Download-URL: https://github.com/Living-with-machines/MapReader/archive/refs/heads/main.zip
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|