Skip to content

Added csm sandbox #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions docs/getting-started/csm-stack/csm-sandbox.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# CSM Sandbox\n",
"\n",
"[Download This Notebook :octicons-file-code-16:](https://raw.githubusercontent.com/DOI-USGS/asc-public-docs/refs/heads/main/docs/getting-started/csm-stack/csm-sandbox.ipynb){ .md-button .md-button--primary } \n",
"[Download Example Data :material-folder-arrow-down:](https://raw.githubusercontent.com/DOI-USGS/asc-public-docs/refs/heads/main/docs/getting-started/csm-stack/image-to-ground/image-to-ground.zip){ .md-button .md-button--primary }\n",
"\n",
"### Install Knoten & Prerequisites\n",
"```sh\n",
"mamba install -c conda-forge knoten=0.4 conda-forge matplotlib ipywidgets ipympl>=0.9.6\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Imports"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib widget\n",
"import os # File Path Joining\n",
"import json # Read ISD as python dictionary\n",
"import copy # Important to be able to modify the ISD\n",
"\n",
"from knoten import csm # Knoten CSM\n",
"\n",
"import matplotlib.pyplot as plt # Math and Plotting Tools\n",
"import ipywidgets as widgets\n",
"from ipywidgets import Layout"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Methods for reading/printing stats"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def print_stats(dict, search_keys):\n",
" for search_key in search_keys:\n",
" print(f\"{search_key+\": \":<25}\" + str(dict[search_key]))\n",
"\n",
"def plot_footprint(lons, lats, aspect):\n",
" plt.close()\n",
" plt.rcParams[\"figure.figsize\"] = aspect\n",
" plt.axes().set_aspect('equal','datalim')\n",
" plt.plot(lons, lats)\n",
" plt.xlabel(\"Longitude (deg)\")\n",
" plt.ylabel(\"Latitude (deg)\")\n",
" plt.title(\"CSM footprint\")\n",
" plt.show()\n",
"\n",
"def plot_footprint_comparison(fp1, fp2, aspect):\n",
" plt.clf() # clear previous figure\n",
" plt.rcParams[\"figure.figsize\"] = aspect # set aspect ratio of plot\n",
" plt.axes().set_aspect('equal','datalim') \n",
" fp1_plot, = plt.plot(fp1[0], fp1[1], 'b') # Plot footprint 1 in blue\n",
"\n",
" margin = 0.001 # boundaries centered on footprint 1\n",
" fp1_lim_x = plt.xlim()\n",
" fp1_lim_y = plt.ylim()\n",
" fp1_lim_x = (fp1_lim_x[0] - margin, fp1_lim_x[1] + margin)\n",
" fp1_lim_y = (fp1_lim_y[0] - margin, fp1_lim_y[1] + margin)\n",
"\n",
" fp2_plot, = plt.plot(fp2[0], fp2[1], 'r') # Plot footprint 2 in red\n",
" plt.title(\"Original vs. Modified Footprint\") # Title and axis labels\n",
" plt.xlabel(\"Longitude (deg)\")\n",
" plt.ylabel(\"Latitude (deg)\")\n",
" fp1_plot.set_label(fp1[2]) # Labels/Legend\n",
" fp2_plot.set_label(fp2[2])\n",
" plt.legend()\n",
" plt.xlim(fp1_lim_x) # Set Size\n",
" plt.ylim(fp1_lim_y)\n",
" plt.show() # Show plot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Stats/Footprint of original ISD"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"focal_length_model: {'focal_length': 352.9271664}\n",
"detector_center: {'line': 0.430442527, 'sample': 2542.96099}\n",
"optical_distortion: {'radial': {'coefficients': [-0.0073433925920054505, 2.8375878636241697e-05, 1.2841989124027099e-08]}}\n",
"center_ephemeris_time: 297088762.2425226\n"
]
}
],
"source": [
"# Load Dict from JSON-style ISD File\n",
"data_dir = 'image-to-ground'\n",
"isd_file = os.path.join(data_dir, 'isd_file.json')\n",
"\n",
"with open(isd_file) as json_file:\n",
" isd_dict = json.load(json_file)\n",
"\n",
"# Print selected values from ISD\n",
"print_stats(isd_dict, ('focal_length_model', 'detector_center', 'optical_distortion', 'center_ephemeris_time'))\n",
"\n",
"# Create Camera Model\n",
"camera = csm.create_csm(isd_file)\n",
"\n",
"# Get the footprint using the model\n",
"boundary = csm.generate_boundary((isd_dict[\"image_lines\"], isd_dict[\"image_samples\"]))\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed this ISD was 1x1 pixel. It would be better to do something that is full sample length with cropped lines. Especially since this is a CTX camera.

"lons, lats, alts = csm.generate_latlon_boundary(camera, boundary)\n",
"\n",
"# # This line can plot the footprint of the original ISD\n",
"# plot_footprint(lons, lats, [5,1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Modify ISD/write to file"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Adjust Sliders to add or subtract from the values at the following ISD Keys:\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "99f757a292504ab19d2b8db31cbd9cd3",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.0, description='Focal Length', layout=Layout(width='600px'), max=0.2…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# clear the plot from any previous footprints/plots\n",
"plt.close()\n",
"\n",
"# Copy the ISD Dictionary, we will modify it and compare to the original.\n",
"isd_dict_mod = copy.deepcopy(isd_dict)\n",
"\n",
"print('Adjust Sliders to add or subtract from the values at the following ISD Keys:')\n",
"\n",
"# Slider Widgets\n",
"wide_lay = Layout(width='600px')\n",
"wide_desc = {'description_width': '150px'}\n",
"@widgets.interact(\n",
" fl_add=widgets.FloatSlider(min=-0.25, max=.25, step=0.001, description='Focal Length', layout=wide_lay, style=wide_desc), \n",
" dcl_add=widgets.FloatSlider(min=-4, max=4, step=0.05, description='Detector Center Line', layout=wide_lay, style=wide_desc),\n",
" dcs_add=widgets.FloatSlider(min=-2.5, max=2.5, step=0.02, description='Detector Center Sample', layout=wide_lay, style=wide_desc),\n",
" opt_x=widgets.FloatSlider(min=-0.001, max=0.001, step=0.00001, description='Optical Distortion X', layout=wide_lay, style=wide_desc, readout_format='.5f'),\n",
" opt_y=widgets.FloatSlider(min=-2e-6, max=2e-6, step=2e-8, description='Optical Distortion Y', layout=wide_lay, style=wide_desc, readout_format='.1e'),\n",
" opt_z=widgets.FloatSlider(min=-1e-8, max=1e-8, step=1e-10, description='Optical Distortion Z', layout=wide_lay, style=wide_desc, readout_format='.1e'),\n",
" ect_add=widgets.FloatSlider(min=-1e-2, max=1e-2, step=1e-4, description='Exposure (Center) Time', layout=wide_lay, style=wide_desc, readout_format='.4f')\n",
" )\n",
"# This function executed whenever one of the slider widgets is adjusted\n",
"def exec_widget_function(fl_add, dcl_add, dcs_add, opt_x, opt_y, opt_z, ect_add):\n",
"\n",
" # If you're curious where the ISD values came from, \n",
" # Detector Center was from NAIF Boresight Line/Sample\n",
" # Optical Distortion was from NAIF OD_K\n",
" # ISIS uses the NAIF Keywords, but Knoten CSM uses other derived ISD values.\n",
"\n",
" new_values = {\n",
" 'focal_length_model': {'focal_length': 352.9271664 + fl_add},\n",
" 'detector_center': {'line': 0.430442527 + dcl_add, 'sample': 2542.96099 + dcs_add},\n",
" 'optical_distortion': {'radial': {'coefficients': [-0.007343 + opt_x, 2.838e-05 + opt_y, 1.284e-08 + opt_z]}},\n",
" 'center_ephemeris_time': 297088762.2425226 + ect_add\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this slider is good, but this is changing there center time, not exposure time. Exposure time is part of the line_scan_rate.

Additionally, might be worth adding sliders or changing values in focal2pixel_lines and focal2pixel_samples

" }\n",
"\n",
" # Modify Values in Dictionary\n",
" for key,value in new_values.items(): \n",
" isd_dict_mod[key] = new_values[key]\n",
"\n",
" # Write ISD to file\n",
" isd_file_mod = os.path.join(data_dir, 'isd_file_mod.json')\n",
" with open(isd_file_mod, 'w') as json_file:\n",
" json.dump(isd_dict_mod, json_file, indent=4)\n",
"\n",
" print_stats(isd_dict_mod, ('focal_length_model', 'detector_center', 'optical_distortion', 'center_ephemeris_time'))\n",
"\n",
" # Create Camera Model\n",
" camera = csm.create_csm(isd_file_mod)\n",
"\n",
" # Get the footprint using the model\n",
" boundary_mod = csm.generate_boundary((isd_dict_mod[\"image_lines\"], isd_dict_mod[\"image_samples\"]))\n",
" lons_mod, lats_mod, alts_mod = csm.generate_latlon_boundary(camera, boundary_mod)\n",
"\n",
" # Plot it\n",
" plot_footprint_comparison((lons, lats, \"Original\"),(lons_mod, lats_mod, \"Modified\"), [7,3])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "knoten",
"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.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
8 changes: 4 additions & 4 deletions docs/getting-started/csm-stack/image-to-ground-tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"metadata": {},
"source": [
"### 2. Generate an ISD from a Cube\n",
"We will use MRO data located in the `data/image_to_ground` folder containing a cube and necessary kernels for ISD (Image Support Data) generation. \n",
"We will use MRO data located in the `image-to-ground` folder containing a cube and necessary kernels for ISD (Image Support Data) generation. \n",
"*Note*: If your cube already has attached spice data, do you not have to specify kernels in the `props` param and can pass in an empty dict `{}` instead."
]
},
Expand All @@ -68,7 +68,7 @@
"import os\n",
"\n",
"# Set local data directory and paths\n",
"data_dir = '../data/image_to_ground'\n",
"data_dir = 'image-to-ground'\n",
"cube_file = os.path.join(data_dir, 'B10_013341_1010_XN_79S172W.cub')\n",
"isd_file = os.path.join(data_dir, 'isd_file.json')\n",
"\n",
Expand Down Expand Up @@ -194,7 +194,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "knoten",
"language": "python",
"name": "python3"
},
Expand All @@ -208,7 +208,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.0"
"version": "3.12.7"
}
},
"nbformat": 4,
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/csm-stack/knoten-camera-tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"metadata": {},
"outputs": [],
"source": [
"data_dir = '../data/image_to_ground'\n",
"data_dir = 'image-to-ground'\n",
"filename = os.path.join(data_dir, \"B10_013341_1010_XN_79S172W.IMG\")\n",
"\n",
"downloader = urllib.request.URLopener()\n",
Expand Down Expand Up @@ -315,7 +315,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "knoten",
"language": "python",
"name": "python3"
},
Expand All @@ -329,7 +329,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
"version": "3.12.7"
}
},
"nbformat": 4,
Expand Down
8 changes: 4 additions & 4 deletions docs/getting-started/using-ale/isd-generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ isd_generate [--arguments] [your-image-name]

!!! example "isd_generate default run, no arguments"

To run isd_generate with no arguments on a .cub named [B10_013341_1010_XN_79S172W.cub](../../getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W.cub):
To run isd_generate with no arguments on a .cub named [B10_013341_1010_XN_79S172W.cub](../../getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W.cub):

```sh
isd_generate B10_013341_1010_XN_79S172W.cub
Expand All @@ -85,7 +85,7 @@ By default, this is your image's name, with a .json file extension (i.e. `B10_01

!!! example "Specifying Output"

[Example .cub](../../getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W.cub)
[Example .cub](../../getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W.cub)

To output to a specified filename, use `--out` or `-o`. This example outputs a 'MyIsd.json' file:

Expand Down Expand Up @@ -121,8 +121,8 @@ When using an NAIF SPICE Data, you can specify a metakernel using the `--kernel`
!!! example "Using a NaifSpice Driver with a metakernel"

Folder with example NAIF Data:
[[Download as .zip](../../getting-started/data/image_to_ground/image-to-ground.zip)]
[[View in GitHub](https://github.com/DOI-USGS/asc-public-docs/tree/main/docs/getting-started/data/image_to_ground)]
[[Download as .zip](../../getting-started/csm-stack/image-to-ground/image-to-ground.zip)]
[[View in GitHub](https://github.com/DOI-USGS/asc-public-docs/tree/main/docs/getting-started/csm-stack/image-to-ground)]

This folder contains NAIF Data consisting of the various kernels
necessary to generate an ISD for the `B10_013341_1010_XN_79S172W` image.
Expand Down
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ nav:
- Home: getting-started/index.md
- CSM Stack:
- Generating an ISD, creating a CSM model, and converting coordinates: getting-started/csm-stack/image-to-ground-tutorial.ipynb
- Knoten - Basic Camera Operations: getting-started/csm-stack/knoten-camera-tutorial.ipynb
- Knoten - Basic Camera Operations: getting-started/csm-stack/knoten-camera-tutorial.ipynb
- CSM Sandbox: getting-started/csm-stack/csm-sandbox.ipynb
- "Using ISIS: First Steps":
- Introduction to ISIS: getting-started/using-isis-first-steps/introduction-to-isis.md
- Locating and Ingesting Image Data: getting-started/using-isis-first-steps/locating-and-ingesting-image-data.md
Expand Down