-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #399 from Living-with-machines/april_workshop
April workshop
- Loading branch information
Showing
6 changed files
with
3,786 additions
and
1 deletion.
There are no files selected for viewing
361 changes: 361 additions & 0 deletions
361
worked_examples/geospatial/workshop_april_2024/Workshop_AprilMay2024_DeepSolo.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,361 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Mapreader Workshop - 30th April - 1st May 2024" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"----" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"First check you have the correct version of MapReader. \n", | ||
"For the April 2024 workshop, this is v1.3.0\n", | ||
"\n", | ||
"This can be downloaded from pypi using `pip install mapreader==1.3.0` or by checking out the repo at [this commit](https://github.com/Living-with-machines/MapReader/releases/tag/v1.3.0)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import mapreader\n", | ||
"assert mapreader.__version__ == '1.3.0'" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"-------------" | ||
] | ||
}, | ||
{ | ||
"attachments": {}, | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Load" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We will start by creating a new ``MapImages`` object by loading our 1000 pixel patches and adding our ``metadata.csv``.\n", | ||
"\n", | ||
"To speed things up for the workshop, we will just load patches corresponding to ``map_75650907.png``." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from mapreader import load_patches" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"my_files = load_patches(patch_paths=\"./patches_1000_pixel/*75650907*png\", parent_paths=\"./maps/map_75650907.png\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"my_files.add_metadata(\"./maps/metadata.csv\", ignore_mismatch=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We then need to run the ``add_coord_increments()`` method, which calculates the change in latitude (dlat) and longitude (dlon) across each pixel.\n", | ||
"This will be used to convert pixel coordinates to geo coordinates." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"my_files.add_coord_increments()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"scrolled": true | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"parent_df, patch_df = my_files.convert_images()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"scrolled": true | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"parent_df.head()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"patch_df.head()" | ||
] | ||
}, | ||
{ | ||
"attachments": {}, | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Detect and recognise text\n", | ||
"\n", | ||
"Now we can load an already trained/fine-tuned text detection model and run the model inference on our patches. \n", | ||
"\n", | ||
"DeepSolo is a text detection and recognition framework so it produces bounding boxes, recognised text outputs and scores." | ||
] | ||
}, | ||
{ | ||
"attachments": {}, | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Set up the DeepSoloRunner" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from mapreader import DeepSoloRunner" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# change these to your own paths, see the docs for more details on how to get these\n", | ||
"cfg_file = \"/Users/rwood/projects/DataCulture/ocr_test/detectron2_etc/DeepSolo/configs/R_50/IC15/finetune_150k_tt_mlt_13_15_textocr.yaml\"\n", | ||
"weights_file = \"/Users/rwood/projects/DataCulture/ocr_test/detectron2_etc/ic15_res50_finetune_synth-tt-mlt-13-15-textocr.pth\"" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"scrolled": true | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"my_runner = DeepSoloRunner(\n", | ||
" patch_df,\n", | ||
" parent_df,\n", | ||
" cfg_file = cfg_file,\n", | ||
" weights_file = weights_file,\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Run on all patches in the patch dataframe" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"patch_predictions = my_runner.run_all(return_dataframe=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"patch_predictions.head()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We can visualise the outputs for each patch with the show method." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"my_runner.show(\n", | ||
" \"patch-4000-2000-5000-3000-#map_75650907.png#.png\",\n", | ||
" figsize=(15, 15),\n", | ||
" border_color=\"r\",\n", | ||
" text_color=\"b\",\n", | ||
" )" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Scale up to parent images" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"The ``convert_to_parent_pixel_bounds()`` method takes all the patch predictions and scales the up to the parent image.\n", | ||
"This means all our bounding boxes are grouped at the parent-level, rather than at the patch-level." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"parent_predictions = my_runner.convert_to_parent_pixel_bounds(return_dataframe=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"parent_predictions.head()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Now we can visualise the outputs for each parent with the show method." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"my_runner.show(\n", | ||
" \"map_75650907.png\", \n", | ||
" figsize=(15, 15),\n", | ||
" border_color=\"r\",\n", | ||
" text_color=\"b\",\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Convert pixel bounds to coordinates" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Since we added our dlat and dlon (coordinate increments), we can convert out pixel coordinates to geo coordinates.\n", | ||
"This will mean our bounding boxes are georeferenced." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"geo_predictions = my_runner.convert_to_coords(return_dataframe=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Saving these outputs will give you a geojson file you can load into a GIS software." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"my_runner.save_to_geojson(\"./deepsolo_outputs.geojson\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "mr_dev", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.10.13" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
Oops, something went wrong.