{"id":22798118,"url":"https://github.com/doi-usgs/autocnet","last_synced_at":"2026-02-07T01:06:47.314Z","repository":{"id":259532967,"uuid":"876337783","full_name":"DOI-USGS/Autocnet","owner":"DOI-USGS","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-24T21:41:50.000Z","size":134240,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-16T13:14:24.298Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DOI-USGS.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.rst","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-21T19:52:35.000Z","updated_at":"2024-10-24T21:30:23.000Z","dependencies_parsed_at":"2024-10-26T17:04:26.376Z","dependency_job_id":null,"html_url":"https://github.com/DOI-USGS/Autocnet","commit_stats":null,"previous_names":["doi-usgs/autocnet"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/DOI-USGS/Autocnet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DOI-USGS%2FAutocnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DOI-USGS%2FAutocnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DOI-USGS%2FAutocnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DOI-USGS%2FAutocnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DOI-USGS","download_url":"https://codeload.github.com/DOI-USGS/Autocnet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DOI-USGS%2FAutocnet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29183330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T00:44:15.062Z","status":"ssl_error","status_checked_at":"2026-02-07T00:35:01.758Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-12T06:08:27.388Z","updated_at":"2026-02-07T01:06:47.277Z","avatar_url":"https://github.com/DOI-USGS.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/AutoCNet_Logo.svg\" alt=\"AutoCNet\" width=200\u003e \n\u003c/p\u003e\n\n# AutoCNet\n\n[![Gitter Chat](https://badges.gitter.im/USGS-Astrogeology/autocnet.svg)](https://gitter.im/USGS-Astrogeology/autocnet?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![Travis-CI](https://travis-ci.org/USGS-Astrogeology/autocnet.svg?branch=dev)](https://travis-ci.org/USGS-Astrogeology/autocnet)\n[![Coveralls](https://coveralls.io/repos/USGS-Astrogeology/autocnet/badge.svg?branch=dev\u0026service=github)](https://coveralls.io/github/USGS-Astrogeology/autocnet?branch=dev)\n[![Docs](https://img.shields.io/badge/Docs-latest-green.svg)](https://usgs-astrogeology.github.io/autocnet/)\n\nAutomated sparse control network generation to support photogrammetric control of planetary image data.\n\n## Documentation\nIs available at: https://autocnet.readthedocs.io/en/dev/\n\n## Installation Instructions\nWe suggest using Anaconda Python to install Autocnet within a virtual environment.  These steps will walk you through the process.\n\n1. [Download](https://www.continuum.io/downloads) and install the Python 3.x Miniconda installer.  Respond ``Yes`` when prompted to add conda to your BASH profile.\n2. Install ISIS.   Follow the \n   [instructions to install ISIS](https://github.com/USGS-Astrogeology/ISIS3#installation) in its own conda \n   environment. With that ISIS environment activated, determine the values for the ISIS environment \n   variables, with a command like this (may vary by your shell):\n\n   `printenv | grep ISIS`\n\n   Copy down the values of ISISROOT and ISISDATA.  Exit the ISIS environment. \n   \n3. Install `mamba`. [`mamba`](https://github.com/mamba-org/mamba) is a fast cross platform package manager that has, in our experience, improved environment solving. The AutoCNet environment is complex and `mamba` is necessary to get a solve. To install `conda install -c conda-forge mamba`.\n4. Install the autocnet environment using the supplied environment.yml file: `mamba env create -n autocnet -f environment.yml` \n5. Activate your environment: `conda activate autocnet`\n6. Ensure ISISROOT and ISISDATA are set in the *autocnet* environment.  One way is to\n   ```\n   conda env config vars set ISISROOT=value-you-wrote-down-from-step-2\n   conda env config vars set ISISDATA=value-you-wrote-down-from-step-2\n   conda deactivate\n   conda activate autocnet\n   ```\n   If you use Jupyter notebooks, you may need to do the following in a cell before importing \n   *autocnet* modules:\n   ```\n   import os\n   os.environ[\"ISISROOT\"] = \"path-you-wrote-down-in-step-2\"\n   os.environ[\"ISISDATA\"] = \"path-you-wrote-down-in-step-2\"\n   ```\n   \n7. If you are going to develop autocnet or would like to use the bleeding edge version: `python setup.py develop`. Otherwise, `conda install -c usgs-astrogeology autocnet`\n\n## How to run the test suite locally\n\n1. Install Docker\n2. Get the Postgresql with Postgis container and run it `docker run --name testdb -e POSTGRES_PASSOWRD='NotTheDefault' -e POSTGRES_USER='postgres' -p 5432:5432 -d mdillon/postgis`\n3. Run the test suite: `pytest autocnet`\n\n## Simple Network Examples:\n\n\n### Setup a project\nThis first example imports the NetworkCandidateGraph object, which is used to orchestrate jobs, manage\na database session, and generally work with the images, points, and measures in\na control network.\n\n```\nfrom autocnet.graph.network import NetworkCandidateGraph\n\n# Make an empty NCG\nncg = NetworkCandidateGraph()\n# Load the configuration file\nncg.config_from_file('config/demo.yml')\n\n# Populate the nodes/edges from the DB\nncg.from_database()\n```\n\nLine by line, this code first imports the network candidate graph, a collection\nof nodes and edges that represents a potential control network.\n`from autocnet.graph.network import NetworkCandidateGraph`.\n\nNext, a network candidate graph is instantiated. `ncg =\nNetworkCandidateGraph()`.\n\nThe network candidate graph (or NCG) is assocaited with a collection of\nPostGreSQL database tables. We have to initiate the database connection via a\nconfiguration file. An example configuration file is\nprovided in the config directory. `ncg.config_from_file('config/demo.yml')`\n\nOnce configured, the images need to be loaded and the graph of potential\noverlapping images generated. We do this with `ncg.from_database()`.\n\nAt this point, you have a fully functioning autocnet project using an NCG. The\nabove snippet assumes that a prepopulated database already exists. Keep reading\nto see how AutoCNet supports importing images from an existing image data\nstore.\n\n### Import images from a data store containing image footprints\nAutocnet does not assume where your image footprints are coming from for\ninitial setup. We do assume that you have a prepopulated database of image\nfootprints with a `geom` column. Otherwise, you could use any software to\ncreate image footprints and populate the footprint database.\n\nTo initialize a project from a data store of image footprints we can do the\nfollowing:\n\n```\n# These lines are pulled from the example above\nfrom autocnet.graph.network import NetworkCandidateGraph\n\nncg = NetworkCandidateGraph()\nncg.config_from_file('config/demo.yml')\n\n# Create the connection \nsource_db_config = {'username':'jay',\n        'password':'abcde',\n        'host':'localhost',\n        'pgbouncer_port':5432,\n        'name':'someothertable'}\n\n# Subset the data store using a spatial query.\ngeom = 'LINESTRING(145 10, 145 10.25, 145.25 10.25, 145.25 10, 145 10)'\nsrid = 104971\noutpath = '/scratch/some/path/for/data'\nquery = f\"SELECT * FROM ctx WHERE ST_INTERSECTS(geom, ST_Polygon(ST_GeomFromText('{geom}'), {srid})) = TRUE\"\nncg.add_from_remote_database(source_db_config, outpath, query_string=query)\n```\n\nHere we create an NCG as above. Then we define a new database connection with\nthe name of the database from which data will be extracted. `source_db_config =\n{'username':'jay', 'password':'abcde', 'host':'localhost',\n'pgbouncer_port':5432, 'name':'someothertable'}.\n\nIn this example, we want to use a spatial query to subset the data. We could\nalso use an attribute query or some combination. The only restriction is that\nthe quert string be valid SQL. `geom = 'LINESTRING(145 10, 145 10.25, 145.25\n10.25, 145.25 10, 145 10)'`\n\nThe PostGIS query requires a valid SRID for the input geometry, so we\nexplicitly define that here. This is the SRID that the footprints are being\nstored in inside of the data store. `srid = 104971` The srid here is a custom\nsrid that has been added to the data store spatial reference table; the id can\nbe any arbitrary number as long as it exists in the spatial reference table.\n\nThe `add_from_remote_database` call copies the image files in the source\ndatabase into a new directory. Here we define that directory. `outpath =\n'/scratch/some/path/for/data'`. \n\nThe query string is then constructed: `query = f\"SELECT * FROM ctx WHERE\nST_INTERSECTS(geom, ST_Polygon(ST_GeomFromText('{geom}'), {srid})) = TRUE\"` \n\nFinally, our database associated with the NCG is populated and the image data\nare copied. `ncg.add_from_remote_database(source_db_config, outpath,\nquery_string=query)`\n\n### Creating a NCG Using a Filelist\nIt is also possible to create a NCG and instantiate an associated database from a\nlist of ISIS cube files that have had footprints created (using *footprintinit*).\n\n```\nfrom autocnet.graph.network import NetworkCandidateGraph\n\nncg = NetworkCandidateGraph.from_filelist(myimages.lis)\n```\n\nThis method can take a bit of time to run if the filelist is large as the data\nare loaded into the database sequentially and then a spatial overlay operation is performed\nto determine how individual images overlap with one another (using the footprints\ngenerated from the a priori sensor pointing.)\n\nThis method performs the following actions:\n- Load each image, as a row, into the Images table of the database. This includes attempting to extract a footprint from the image. The footprint can be read from an ISIS cube if footprint init has been run. Alternatively, experimental support exists for Community Sensor Model sensors developed by USGS.\n- Use the database to compute the overlapping geometries between each of the images. For large data sets this can be a costly, one time operation. Limiting the number of geometries in image footprints can significantly improve performance. For each overlap, a row is added to the Overlay table. This table tracks the overlapping geometries and the images that intersect those geometries.\n- Return a NewtorkCandidateGraph where each node represents and image and each edge represents a spatial overlap between said images.\n\n### Operations on the NCG: Database Rows\nAfter we have an NCG, we want to perform operations on the graph or on database\nrows associated with the graph (e.g., the Points, Measures, or Image Overlaps).\nWe use a functional approach where an arbitray function can be applied to an\niterable associated with the graph. Here is a concrete example to help\nillustrate what this looks like in practice.\n\n```\nfrom autocnet.graph.network import NetworkCandidateGraph\n\nncg = NetworkCandidateGraph()\nncg.config_from_file('/home/jlaura/autocnet_projects/demo.yml')\nncg.from_database()\n\n\n# Define a function to govern the distribution of points in the North/South direction\ndef ns(x):\n    from math import ceil\n    return ceil(round(x,1)*8)\n\n# Define a function to govern the distribution of points in the East/West direction\ndef ew(x):\n    from math import ceil\n    return ceil(round(x,1)*1)\n\n# Pack a set of kwargs into a keyword that the called function is expecting\ndistribute_points_kwargs = {'nspts_func':ns, 'ewpts_func':ew}\n\n# Apply a function on an iterable\nnjobs = ncg.apply('spatial.overlap.place_points_in_overlap', \n                  on='overlaps', \n                  cam_type='isis',\n                  distribute_points_kwargs=distribute_points_kwargs)\n```\n\nMost of the above is either familiar boiler plate or a pair of helper functions\nthat we want to pass in. The interesting stuff is happening in:\n\n```\nnjobs = ncg.apply('spatial.overlap.place_points_in_overlap',\n                  on='overlaps',\n                  cam_type='isis',\n                  distribute_points_kwargs=distribute_points_kwargs)\n```\n\nHere, we are applying the `spatial.overlap.place_points_in_overlap` function on\nan iterable (`overlaps`) with three keyword arguments (that the function is\nexpecting). The syntax for the function is module.submodule.function_name'.\nWhere the submodule can be repeated, e.g.,\nmodule.submodule.subsubmodule.function_name.\n\nIt is possible to use a similar block to, for example, apply some subpixel\nregistration algorithm: \n\n`njobs = ncg.apply('matcher.subpixel.subpixel_register_point', on='points')`\n\nor to apply a second pass subpixel alignment on only measures meeting some\ncriteria:\n\n```\nfilters = {'ignore' : True}  # A database filter in the form column name : equality\nnjobs = ncg.apply('matcher.subpixel.subpixel_register_measure',\n                  on='measures',\n                  filters=filters)\n```\n\n### Operations on the NCG: Nodes and Edges\nJust like the above example, it is possible to apply arbitrary functions to\nnodes and edges in a NetworkCandidateGraph.\n\n```\nncg = NetworkCandidateGraph()\nncg.config_from_file('/home/jlaura/autocnet_projects/demo.yml')\nncg.from_database()\n\nnjobs = ncg.apply('network_to_matches', on='edges')\n```\n\nAfter the standard boilerplate, the `network_to_matches` function is applied to\nevery edge in the graph. This function takes the points and measures from the\ndatabase and expands them so that every edge now has the pairwise\n(measure-to-measure) information that is frequently quite useful when using\ncomputer vision techniques. Note that the function to be called is not longer\nbeing specificed with the import path (e.g.,\nspatial.overlap.place_points_in_overla-). Note that the function to be called is no longer\nbeing specificed with the import path (e.g., spatial.overlap.place_points_in_overlaps) because \nonly Edge or NetworkEdge methods can be called on the autocnet Edge or NetworkEdge objects.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoi-usgs%2Fautocnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoi-usgs%2Fautocnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoi-usgs%2Fautocnet/lists"}