mapreader 1.2.0__tar.gz → 1.3.1__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.
Files changed (48) hide show
  1. {mapreader-1.2.0 → mapreader-1.3.1}/PKG-INFO +1 -1
  2. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/__init__.py +10 -0
  3. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/_version.py +3 -3
  4. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/sheet_downloader.py +73 -26
  5. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/tile_merging.py +22 -8
  6. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/load/images.py +1 -1
  7. mapreader-1.3.1/mapreader/spot_text/deepsolo_runner.py +643 -0
  8. mapreader-1.3.1/mapreader/spot_text/dptext_detr_runner.py +434 -0
  9. mapreader-1.3.1/mapreader/utils/__init__.py +0 -0
  10. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/PKG-INFO +1 -1
  11. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/SOURCES.txt +3 -0
  12. {mapreader-1.2.0 → mapreader-1.3.1}/tests/test_sheet_downloader.py +158 -51
  13. {mapreader-1.2.0 → mapreader-1.3.1}/LICENSE +0 -0
  14. {mapreader-1.2.0 → mapreader-1.3.1}/README.md +0 -0
  15. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/annotate/__init__.py +0 -0
  16. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/annotate/annotator.py +0 -0
  17. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/annotate/utils.py +0 -0
  18. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/classify/__init__.py +0 -0
  19. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/classify/classifier.py +0 -0
  20. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/classify/custom_models.py +0 -0
  21. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/classify/datasets.py +0 -0
  22. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/classify/load_annotations.py +0 -0
  23. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/__init__.py +0 -0
  24. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/data_structures.py +0 -0
  25. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/downloader.py +0 -0
  26. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/downloader_utils.py +0 -0
  27. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/download/tile_loading.py +0 -0
  28. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/load/__init__.py +0 -0
  29. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/load/geo_utils.py +0 -0
  30. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/load/loader.py +0 -0
  31. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/process/__init__.py +0 -0
  32. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/process/post_process.py +0 -0
  33. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/process/process.py +0 -0
  34. {mapreader-1.2.0/mapreader/utils → mapreader-1.3.1/mapreader/spot_text}/__init__.py +0 -0
  35. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/utils/compute_and_save_stats.py +0 -0
  36. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader/utils/slice_parallel.py +0 -0
  37. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/dependency_links.txt +0 -0
  38. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/entry_points.txt +0 -0
  39. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/not-zip-safe +0 -0
  40. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/requires.txt +0 -0
  41. {mapreader-1.2.0 → mapreader-1.3.1}/mapreader.egg-info/top_level.txt +0 -0
  42. {mapreader-1.2.0 → mapreader-1.3.1}/setup.cfg +0 -0
  43. {mapreader-1.2.0 → mapreader-1.3.1}/setup.py +0 -0
  44. {mapreader-1.2.0 → mapreader-1.3.1}/tests/test_annotator.py +0 -0
  45. {mapreader-1.2.0 → mapreader-1.3.1}/tests/test_geo_pipeline.py +0 -0
  46. {mapreader-1.2.0 → mapreader-1.3.1}/tests/test_import.py +0 -0
  47. {mapreader-1.2.0 → mapreader-1.3.1}/tests/test_post_processing.py +0 -0
  48. {mapreader-1.2.0 → mapreader-1.3.1}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapreader
3
- Version: 1.2.0
3
+ Version: 1.3.1
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
@@ -12,6 +12,16 @@ from mapreader.classify.datasets import PatchContextDataset
12
12
  from mapreader.classify.classifier import ClassifierContainer
13
13
  from mapreader.classify import custom_models
14
14
 
15
+ try:
16
+ from mapreader.spot_text.deepsolo_runner import DeepSoloRunner
17
+ except ImportError:
18
+ pass
19
+
20
+ try:
21
+ from mapreader.spot_text.dptext_detr_runner import DPTextDETRRunner
22
+ except ImportError:
23
+ pass
24
+
15
25
  from mapreader.process import process
16
26
 
17
27
  from mapreader.annotate.annotator import Annotator
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-04-08T09:00:00+0100",
11
+ "date": "2024-05-03T13:32:40+0100",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "e9d119ffa6946e723f7977ddd7add0c9bcce34d8",
15
- "version": "1.2.0"
14
+ "full-revisionid": "3d7ab10b0f7bc0833e122a65a4d4bd608ca62fcd",
15
+ "version": "1.3.1"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -533,7 +533,7 @@ class SheetDownloader:
533
533
  """
534
534
  self.merger = TileMerger(output_folder=f"{path_save}/")
535
535
 
536
- def _check_map_sheet_exists(self, feature: dict) -> bool:
536
+ def _check_map_sheet_exists(self, feature: dict, metadata_fname) -> bool:
537
537
  """
538
538
  Checks if a map sheet is already saved.
539
539
 
@@ -544,51 +544,87 @@ class SheetDownloader:
544
544
  Returns
545
545
  -------
546
546
  bool
547
- True if file exists, False if not.
547
+ img_path if file exists, False if not.
548
548
  """
549
- map_name = str("map_" + feature["properties"]["IMAGE"])
550
549
  path_save = self.merger.output_folder
551
- if os.path.exists(f"{path_save}{map_name}.png"):
550
+
551
+ try:
552
+ # get image id with same coords in metadata
553
+ existing_metadata_df = pd.read_csv(
554
+ f"{path_save}{metadata_fname}", sep=",", index_col=0
555
+ )
556
+ except FileNotFoundError:
557
+ return False
558
+
559
+ polygon = get_polygon_from_grid_bb(feature["grid_bb"])
560
+ if str(polygon.bounds) in existing_metadata_df["coordinates"].values:
561
+ image_id = existing_metadata_df[
562
+ existing_metadata_df["coordinates"] == str(polygon.bounds)
563
+ ].iloc[0]["name"]
564
+ else:
565
+ return False # coordinates not in metadata means image doesn't exist
566
+
567
+ if os.path.exists(f"{path_save}{image_id}"):
552
568
  try:
553
- mpimg.imread(f"{path_save}{map_name}.png")
554
- print(
555
- f'[INFO] "{path_save}{map_name}.png" already exists. Skipping download.'
556
- )
557
- return True
569
+ # check image is valid
570
+ mpimg.imread(f"{path_save}{image_id}")
571
+ return image_id
558
572
  except OSError:
559
573
  return False
560
574
  return False
561
575
 
562
- def _download_map(self, feature: dict, download_in_parallel: bool = True) -> bool:
576
+ def _download_map(
577
+ self,
578
+ feature: dict,
579
+ existing_id: str | bool,
580
+ download_in_parallel: bool = True,
581
+ overwrite: bool = False,
582
+ ) -> str | bool:
563
583
  """
564
584
  Downloads a single map sheet and saves as png file.
565
585
 
566
586
  Parameters
567
587
  ----------
568
588
  feature : dict
589
+ The feature for which to download the map sheet.
590
+ existing_id : str | bool
591
+ The existing image id if the map sheet already exists.
592
+ download_in_parallel : bool, optional
593
+ Whether to download tiles in parallel, by default ``True``.
594
+ overwrite : bool, optional
595
+ Whether to overwrite existing maps, by default ``False``.
569
596
 
570
597
  Returns
571
598
  -------
572
- bool
573
- True if map was downloaded successfully, False if not.
599
+ str or bool
600
+ image path if map was downloaded successfully, False if not.
574
601
  """
575
- map_name = str("map_" + feature["properties"]["IMAGE"])
576
602
  self.downloader.download_tiles(
577
603
  feature["grid_bb"], download_in_parallel=download_in_parallel
578
604
  )
579
- success = self.merger.merge(feature["grid_bb"], map_name)
580
- if success:
581
- print(f'[INFO] Downloaded "{map_name}.png"')
605
+
606
+ if existing_id is False:
607
+ map_name = f"map_{feature['properties']['IMAGE']}"
608
+ else:
609
+ map_name = existing_id[:-4] # remove file extension (assuming .png)
610
+
611
+ img_path = self.merger.merge(
612
+ feature["grid_bb"], file_name=map_name, overwrite=overwrite
613
+ )
614
+
615
+ if img_path is not False:
616
+ print(f'[INFO] Downloaded "{img_path}"')
582
617
  else:
583
- print(f'[WARNING] Download of "{map_name}.png" was unsuccessful.')
618
+ print(f'[WARNING] Download of "{img_path}" was unsuccessful.')
584
619
 
585
620
  shutil.rmtree(DEFAULT_TEMP_FOLDER)
586
- return success
621
+ return img_path
587
622
 
588
623
  def _save_metadata(
589
624
  self,
590
625
  feature: dict,
591
626
  out_filepath: str,
627
+ img_path: str,
592
628
  metadata_to_save: dict | None = None,
593
629
  **kwargs: dict | None,
594
630
  ) -> None:
@@ -602,6 +638,8 @@ class SheetDownloader:
602
638
  The feature for which to extract the metadata from
603
639
  out_filepath : str
604
640
  The path to save metadata csv.
641
+ img_path : str
642
+ The path to the downloaded map sheet.
605
643
  metadata_to_save : dict, optional
606
644
  A dictionary containing column names (str) and metadata keys (str or list) to save to metadata csv.
607
645
  Multilayer keys should be passed as a list, i.e. ["key1","key2"] will search for ``self.features[i]["key1"]["key2"]``.
@@ -631,7 +669,7 @@ class SheetDownloader:
631
669
  metadata_dict = {col: None for col in metadata_cols}
632
670
 
633
671
  # get default metadata
634
- metadata_dict["name"] = str("map_" + feature["properties"]["IMAGE"] + ".png")
672
+ metadata_dict["name"] = os.path.basename(img_path)
635
673
  metadata_dict["url"] = str(feature["properties"]["IMAGEURL"])
636
674
  if not self.published_dates:
637
675
  date_col = kwargs.get("date_col", None)
@@ -705,16 +743,25 @@ class SheetDownloader:
705
743
  """
706
744
 
707
745
  for feature in tqdm(features):
708
- if not overwrite:
709
- if self._check_map_sheet_exists(feature):
710
- continue
711
- success = self._download_map(
712
- feature, download_in_parallel=download_in_parallel
746
+ existing_id = self._check_map_sheet_exists(feature, metadata_fname)
747
+ if (
748
+ not overwrite and existing_id is not False
749
+ ): # if map already exists and overwrite is False then skip
750
+ print(f'[INFO] "{existing_id}" already exists. Skipping download.')
751
+ continue
752
+ img_path = self._download_map(
753
+ feature,
754
+ existing_id,
755
+ download_in_parallel=download_in_parallel,
756
+ overwrite=overwrite,
713
757
  )
714
- if success:
758
+ if img_path is not False:
715
759
  metadata_path = f"{path_save}/{metadata_fname}"
716
760
  self._save_metadata(
717
- feature=feature, out_filepath=metadata_path, **kwargs
761
+ feature=feature,
762
+ out_filepath=metadata_path,
763
+ img_path=img_path,
764
+ **kwargs,
718
765
  )
719
766
 
720
767
  def download_all_map_sheets(
@@ -142,7 +142,12 @@ class TileMerger:
142
142
  tile_size = img_size[0]
143
143
  return tile_size
144
144
 
145
- def merge(self, grid_bb: GridBoundingBox, file_name: str | None = None) -> bool:
145
+ def merge(
146
+ self,
147
+ grid_bb: GridBoundingBox,
148
+ file_name: str | None = None,
149
+ overwrite: bool = False,
150
+ ) -> str | bool:
146
151
  """Merges cells contained within GridBoundingBox.
147
152
 
148
153
  Parameters
@@ -151,11 +156,13 @@ class TileMerger:
151
156
  GridBoundingBox containing tiles to merge
152
157
  file_name : Union[str, None], optional
153
158
  Name to use when saving map
154
-
159
+ If None, default name will be used, by default None
160
+ overwrite : bool, optional
161
+ Whether or not to overwrite existing files, by default False
155
162
  Returns
156
163
  -------
157
- bool
158
- True if file has successfully downloaded, False if not.
164
+ str or bool
165
+ out path if file has successfully downloaded, False if not.
159
166
  """
160
167
  os.makedirs(self.output_folder, exist_ok=True)
161
168
 
@@ -191,11 +198,18 @@ class TileMerger:
191
198
  file_name = self._get_output_name(grid_bb)
192
199
 
193
200
  out_path = f"{self.output_folder}{file_name}.{self.img_output_format[0]}"
201
+ if not overwrite:
202
+ i = 1
203
+ while os.path.exists(out_path):
204
+ out_path = (
205
+ f"{self.output_folder}{file_name}_{i}.{self.img_output_format[0]}"
206
+ )
207
+ i += 1
194
208
  merged_image.save(out_path, self.img_output_format[1])
195
- success = True if os.path.exists(out_path) else False
196
- if success:
197
- logger.info(f"Merge successful! The image has been stored at '{out_path}'")
198
- else:
209
+ success = out_path if os.path.exists(out_path) else False
210
+ if success is False:
199
211
  logger.warning(f"Merge unsuccessful! '{out_path}' not saved.")
212
+ else:
213
+ logger.info(f"Merge successful! The image has been stored at '{out_path}'")
200
214
 
201
215
  return success
@@ -1753,7 +1753,7 @@ See https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes for mor
1753
1753
  counter=-1,
1754
1754
  )
1755
1755
 
1756
- ax.set_title(image_id)
1756
+ ax.set_title(parent_id)
1757
1757
  figures.append(fig)
1758
1758
 
1759
1759
  if column_to_plot and plot_histogram: