Introduction

This tutorial demonstrates how to automate photogrammetric correction of drone images and generate reality mapping products using the ArcGIS API for Python. You'll learn to create Digital Surface Models (DSM), Digital Terrain Models (DTM), true ortho imagery, and DSM mesh. In this workflow, you will process a collection of nadir drone images through the complete reality mapping pipeline, including:

  • Creating a project
  • Create a mission
  • Perform block adjustment and refine the adjustment using Ground Control Points (GCP)
  • Generate true ortho and DSM products

To learn about more about reality mapping concepts, workflows and configurations, see the Introduction to reality mapping guide.

A collection of 195 drone images covering a section of the Esri campus, California, is provided for this tutorial. Each image has embedded EXIF metadata which is used along with the supplied GCP’s to support the block adjustment process.

Download the tutorial dataset, unzip it, and save contents to your local system, for example C:\SampleData\RM_Drone_tutorial.

Getting Started

Reality mapping capability through ArcGIS API for Python requires ArcGIS Enterprise federated with a Reality Server license. See the configuration instruction for setup details.

Once your environment is configured, import the required class and module:

  • GIS class: Represents the organizational deployment and accesses classes to manage content, users, and groups

  • arcgis.raster.realitymapping submodule provides the functionality to automate reality mapping tasks in the server environment. The reality mapping module is available with ArcGIS API for Python (version >= 2.4.2)

from arcgis.gis import GIS
from arcgis.raster import realitymapping

Establish a connection to your ArcGIS Enterprise portal and verify that reality mapping is supported in your environment.

note: Change credentials to match your organization credentials.

#connect to GIS
gis = GIS(
    url= "https://yourportal.domain.com/portal",
    username= "your username",
    password= "your password"
)

# confirm that reality mapping is supported
realitymapping.is_supported(gis)

Step 1: Create a Project

The first step is to create a reality mapping project using the Project class of the reality mapping module.

# Create a new project
project = realitymapping.Project("DroneProject")
project
<Project - DroneProject>

A project is a top-level workspace for managing reality mapping activities. Initializing a new a project creates a new portal folder and a reality mapping project item inside that folder. The project item contains the basic information (e.g. project name, group name, workspace name, etc.) that defines a reality mapping project.

# Project item id
project.item.itemid
'ebf8a46d74d54817a0d303cec38ee451'

Step 2: Create a Mission

The next step is to create a mission, which contains all related imagery and processed data products for managing a single data capture session. Creating a mission creates a supporting image collection for the source rasters. So we need to first define the type, properties and path of the source rasters using the ImageSource class.

# Create an image source of UAV type
uav_src = realitymapping.ImageSource("UAV/UAS")
# Define the estimated flying height
uav_src.raster_type.estimate_flight_height = 330
# Define the source rasters' path
uav_src.input_data = r"C:\SampleData\RM_Drone_Tutorial\Images"

Other properties specific to the UAV/UAS image source object we just created can be defined similarly to the estimate_flight_height assignment in the cell above. To see the possible attributes, use the attributes property of the raster_type instance.

# See other attributes
uav_src.raster_type.attributes
{'name': 'UAV/UAS',
 'camera_info': None,
 'gps_info': None,
 'processing_template': None,
 'dem': None,
 'averagezdem': None,
 'constant_z': None,
 'zfactor': None,
 'zoffset': None,
 'correct_geoid': None,
 'estimate_flight_height': 330,
 'is_altitude_flight_height': None,
 'minimum_flight_height': None,
 'stretch_type': None,
 'scale_factor': None,
 'valid_range': None}

Now we can create the mission (and image collection) using the image source object

mission = project.create_mission(
    image_sources= uav_src,
    out_sr = {"wkid": 32611, "vcsWkid": 5773}
)
mission
# check the number of images in the image collection
print(mission.image_count)

# Show specifc image in the collection
mission.image_collection.layers[0].filter_by("OBJECTID=69")
195
<ImageryLayer url:"https://devmg00159.esri.com/server/rest/services/Hosted/reality_pyapi_20260407103529/ImageServer">

At this point, your imagery is organized but not yet geometrically adjusted. The next step is to perform block adjustment.

Step 3: Perform Adjustment

Block adjustment involves using tie points to calculate the exterior orientation for each each image such that they are consistent with neighboring images (Relative orientation). A more refined adjustment can then be performed using Ground Control Points (GCP). Read more about adjustment here.

3.1 Compute Initial Block Adjustment

To perform block adjustment, we call the compute_sensor_model() method of the mission object. The compute_sensor_model() method computes block adjustment for the image collection and applies the frame transform to the images based on the raster type information used when creating the image collection. It also generates the control points feature class, solution table, solution points feature class, and flight path feature class.

note: These feature classes and tables will be saved in raster store and will not be created in the ArcGIS Enterprise as separate items.

For preliminary quality purposes, we can perform block adjustment at quick or full mode. Quick mode computes tie points and adjustment at 8x of the source imagery resolution while full mode adjust the images in Quick mode then at 1x of the source imagery resolution. Running under either of these two modes will make it ready for another block adjustment run with more ground control points and matching tie points later on.

mission.compute_sensor_model(mode="Full", location_accuracy="High")

The adjustment report contain information about the quality of bundle block adjustment

mission.generate_report(report_format= "HTML")

Confirm that everything looks goods for the quality check of the adjustment report, except for the warning that Ground Control Points and Check Points are not used in the adjustment.

3.2 Add ground control points (optional)

The reality mapping workflow may need to run adjustment twice. The initial block adjustment is computed to generate the tie points among overlapping images for preliminary results. The second block adjustment is computed with ground control points for refined results. Note that this step is optional.

The workflow for adding GCP involves:

  1. Prepare input control points for the data : The first step is to define the ground control points. This will be a list of GCPs (see figure below) and for each gcp in the list, a tie point on at least one image needs to be specified.
  2. Match control points : Next, we will use match_control_points to find matching tie points on other overlapping images.
  3. Update the control points feature class : Then, we will run edit_control_points to update the control point feature class.

3.2.1 Prepare the GCP

The location information of the control points for this tutorial data is shown in the picture below.

The first GCP ("x": 481759.9533, "y": 3768700.799,"z": 391.1696) appears in a couple of images including DJI_0071.JPG image whose image ID in the image collection is 69. Open this image with paint or other photo editor and confirm that the image coordinate of the control point marker is 4108, -2929. Note that the column value is negative because the reference for the image coordinate system is top-up.

After determining the location and tie points of other control points in similar approach, the input control points variable is defined below.

To use some of the control points as check point, specify the type as 3.

input_gcp = [
    {
         "pointId": 1,"x": 481759.9533, "y": 3768700.799,"z": 391.1696,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.013,"zAccuracy": 0.052,
         "imagePoints": [
             {
              "imageID": 69,
              "u": 4108,]
              "v": -2929
             }
         ] 
    },
    {
        "pointId": 2, "gcptype": 3, "x": 481759.9227, "y": 3768667.486,"z": 391.0711,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.013,"zAccuracy": 0.044,
         "imagePoints": [
             {
              "imageID": 69,
              "u": 2135,
              "v": -1086
             }
          ] 
    },
    {
        "pointId": 3, "x": 481763.9006, "y": 3768653.822,"z": 390.9542,
        "spatialReference": {"wkid":26911, "vcsWkid": 5773},
        "xyAccuracy": 0.012,"zAccuracy": 0.044,
        "imagePoints": [
            {
             "imageID": 51,
             "u": 2598,
             "v": -3113
            }
         ] 
    },
    {
        "pointId": 4,"x": 481809.5816, "y": 3768635.463,"z": 390.0384,
        "spatialReference": {"wkid":26911, "vcsWkid": 5773},
        "xyAccuracy": 0.03,"zAccuracy": 0.1,
        "imagePoints": [
            {
             "imageID": 36,
             "u": 1366,
             "v": -2462
            }
        ] 
    },
    {
        "pointId": 5,"x": 481833.5886, "y": 3768652.399,"z": 391.8996,
        "spatialReference": {"wkid":26911, "vcsWkid": 5773},
        "xyAccuracy": 0.019,"zAccuracy": 0.075,
        "imagePoints": [
            {
             "imageID": 15,
             "u": 2664,
             "v": -2159
            }
        ] 
     },
     {
         "pointId": 6,"x": 481877.181, "y": 3768656.118,"z": 391.1185,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.026,"zAccuracy": 0.085,
         "imagePoints": [
             {
              "imageID": 8,
              "u": 2518,
              "v": -3162
             }
         ] 
     },
     {
         "pointId": 7, "gcptype": 3, "x": 481870.2391, "y": 3768697.345,"z": 392.046,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.017,"zAccuracy": 0.057,
         "imagePoints": [
             {
              "imageID": 28,
              "u": 1360,
              "v": -724
             }
         ] 
     },
     {
         "pointId": 8,"x": 481870.28, "y": 3768711.083,"z": 392.0088,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.022,"zAccuracy": 0.065,
         "imagePoints": [
             {
              "imageID": 28,
              "u": 2170,
              "v": -1490
             }
         ] 
     },
     {
         "pointId": 9,"x": 481856.2017, "y": 3768735.404,"z": 391.5458,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.012,"zAccuracy": 0.036,
         "imagePoints": [
             {
              "imageID": 58,
              "u": 3152,
              "v": -871
             }
         ] 
     },
     {
         "pointId": 11, "gcptype": 3, "x": 481812.8916, "y": 3768653.304,"z": 392.924,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.023,"zAccuracy": 0.094,
         "imagePoints": [
             {
              "imageID": 35,
              "u": 2132,
              "v": -2613
             }
         ] 
     },
     {
         "pointId": 12,"x": 481774.7308, "y": 3768681.601,"z": 392.5825,
         "spatialReference": {"wkid":26911, "vcsWkid": 5773},
         "xyAccuracy": 0.017,"zAccuracy": 0.051,
         "imagePoints": [
             {
              "imageID": 68,
              "u": 2081,
              "v": -1625
             }
         ] 
     }
]

3.2.2 Match Control Points

We have created a GCP with atleast one tie point but each tie point needs to be identified in other overlapping images. Manually creating tie points for all overlapping images is labor intensive. For a given ground control point and initial tie point in one of the overlapping images, match_control_points() will help find all remaining tie points on all other image items of the image collection.

control_point_sets = mission.match_control_points(
                        control_points=input_gcp, 
                        similarity="High"
                    )
control_point_sets
[{'pointID': 1,
  'x': 481759.95329979766,
  'y': 3768700.7990001333,
  'z': 391.1695999999938,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.013,
  'ZAccuracy': 0.052,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 69,
    'x': 3076.754447380615,
    'y': -3552.4940620410443,
    'u': 4108,
    'v': -2929,
    'score': -1},
   {'imageID': 67,
    'x': 4412.319591530715,
    'y': -1672.551351078611,
    'u': 3991.1201923668373,
    'v': -701.9304084823648,
    'score': 0.99},
   {'imageID': 68,
    'x': 3773.268635764324,
    'y': -2637.8794522488297,
    'u': 4054.6087874864675,
    'v': -1812.1916272282103,
    'score': 0.99},
   {'imageID': 79,
    'x': 4444.966258914339,
    'y': -2492.7150899575186,
    'u': 3590.8421693692017,
    'v': -199.15384796311332,
    'score': 0.99},
   {'imageID': 80,
    'x': 3365.584176242943,
    'y': -2571.775692821053,
    'u': 3571.572383534964,
    'v': -1315.6581140197386,
    'score': 0.99},
   {'imageID': 81,
    'x': 2286.7551749682148,
    'y': -2751.1023864125814,
    'u': 3571.939181929828,
    'v': -2425.3211746484612,
    'score': 0.99},
   {'imageID': 90,
    'x': 19.808015248024503,
    'y': -1664.7818872623757,
    'u': 144.23032970724853,
    'v': -2651.435834911568,
    'score': 0.99},
   {'imageID': 148,
    'x': 3380.742446572975,
    'y': -2279.6932698433284,
    'u': 3513.0094538094995,
    'v': -1682.3342891524162,
    'score': 0.99},
   {'imageID': 149,
    'x': 2601.7925313611986,
    'y': -3103.5396875894166,
    'u': 3544.5203392543162,
    'v': -2824.4361907153125,
    'score': 0.99},
   {'imageID': 165,
    'x': 2910.755691092457,
    'y': -3186.082973317136,
    'u': 4105.762280872701,
    'v': -1922.1209632981622,
    'score': 0.99},
   {'imageID': 166,
    'x': 1832.2098451322954,
    'y': -3457.324002311616,
    'u': 4154.989955507869,
    'v': -3036.0969264626056,
    'score': 0.99},
   {'imageID': 147,
    'x': 4133.228848982127,
    'y': -1436.9895489078115,
    'u': 3452.0470452278814,
    'v': -562.7118781145841,
    'score': 0.99},
   {'imageID': 89,
    'x': 192.67083757192665,
    'y': -1013.6762805092394,
    'u': 74.78863438460075,
    'v': -1617.5494142074554,
    'score': 0.99},
   {'imageID': 140,
    'x': 1441.3449233569445,
    'y': 392.78349671589615,
    'u': 266.73699514433247,
    'v': -2524.878821305999,
    'score': 0.89}]},
 {'pointID': 2,
  'GCPType': 3,
  'x': 481759.9226997986,
  'y': 3768667.4860001355,
  'z': 391.071100000001,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.013,
  'ZAccuracy': 0.044,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 69,
    'x': 2749.1700926007916,
    'y': -871.1305040058801,
    'u': 2134,
    'v': -1085,
    'score': -1},
   {'imageID': 163,
    'x': 2774.2123023456497,
    'y': -1220.699174441084,
    'u': 2146.286958089481,
    'v': -1690.4805997345284,
    'score': 0.99},
   {'imageID': 164,
    'x': 1677.6084348782692,
    'y': -1465.393940788625,
    'u': 2189.3341103167063,
    'v': -2797.706479688926,
    'score': 0.99},
   {'imageID': 51,
    'x': 1473.0456932232464,
    'y': -1273.85199322182,
    'u': 1576.2445358285595,
    'v': -2566.483152972315,
    'score': 0.99},
   {'imageID': 70,
    'x': 2077.49521487329,
    'y': -1717.1743572327193,
    'u': 2166.6359393201656,
    'v': -2170.873723100236,
    'score': 0.99},
   {'imageID': 71,
    'x': 1368.7783432416286,
    'y': -2538.2058486989154,
    'u': 2186.8626953987696,
    'v': -3264.933896025072,
    'score': 0.99},
   {'imageID': 162,
    'x': 3876.749958605373,
    'y': -1018.070222364905,
    'u': 2113.9900584061224,
    'v': -572.5477068557011,
    'score': 0.99},
   {'imageID': 50,
    'x': 2404.229505317886,
    'y': -638.7285943464785,
    'u': 1560.3588559779744,
    'v': -1459.5599384221214,
    'score': 0.99},
   {'imageID': 174,
    'x': 3718.993250587781,
    'y': -664.1363655978421,
    'u': 1592.7227841603506,
    'v': -820.7919221065329,
    'score': 0.99},
   {'imageID': 175,
    'x': 2545.494177751799,
    'y': -670.0596026817345,
    'u': 1571.0035324823523,
    'v': -1925.7906019150935,
    'score': 0.99},
   {'imageID': 176,
    'x': 1434.4114511025696,
    'y': -732.1170872695743,
    'u': 1536.855867178606,
    'v': -3026.492126606553,
    'score': 0.99},
   {'imageID': 49,
    'x': 3309.1822219273754,
    'y': -18.236364017463984,
    'u': 1541.0957680895074,
    'v': -353.3049427777321,
    'score': 0.98}]},
 {'pointID': 3,
  'x': 481763.90059979743,
  'y': 3768653.822000132,
  'z': 390.95419999999285,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.012,
  'ZAccuracy': 0.044,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 50,
    'x': 2507.9281997737044,
    'y': -1785.2686066913475,
    'u': 2580,
    'v': -1994,
    'score': -1},
   {'imageID': 51,
    'x': 1587.8673065244654,
    'y': -2427.359170577172,
    'u': 2598.5083295626578,
    'v': -3113.0515131743723,
    'score': 0.99},
   {'imageID': 70,
    'x': 1661.0181805266761,
    'y': -687.823420735928,
    'u': 1180.6430871907087,
    'v': -1660.1623516447921,
    'score': 0.99},
   {'imageID': 71,
    'x': 980.65745959487,
    'y': -1476.8232673009427,
    'u': 1192.3646933027476,
    'v': -2728.1451656633717,
    'score': 0.99},
   {'imageID': 161,
    'x': 3964.877803525675,
    'y': -521.59979532857,
    'u': 1565.4927545883556,
    'v': -468.0019178905559,
    'score': 0.99},
   {'imageID': 163,
    'x': 1684.1791202953177,
    'y': -876.275058604431,
    'u': 1634.7435152211503,
    'v': -2712.792575534971,
    'score': 0.99},
   {'imageID': 175,
    'x': 3577.4738322530056,
    'y': -1181.2960810075267,
    'u': 2158.768902757704,
    'v': -935.4037559284369,
    'score': 0.99},
   {'imageID': 176,
    'x': 2471.374752041498,
    'y': -1235.2134895300587,
    'u': 2126.783577449549,
    'v': -2036.350137634999,
    'score': 0.99},
   {'imageID': 177,
    'x': 1375.2050297284136,
    'y': -1281.6960410918227,
    'u': 2094.325563024626,
    'v': -3139.8772431414563,
    'score': 0.99},
   {'imageID': 49,
    'x': 3429.4625232933136,
    'y': -1154.725902232373,
    'u': 2557.202095425642,
    'v': -876.3752284546748,
    'score': 0.98},
   {'imageID': 36,
    'x': 5087.287981841588,
    'y': -1444.2640772891727,
    'u': 4969.355941652031,
    'v': -996.0787854594422,
    'score': 0.98},
   {'imageID': 69,
    'x': 2311.719142737285,
    'y': 132.4877269079666,
    'u': 1153.9100891470414,
    'v': -597.1110777233248,
    'score': 0.98}]},
 {'pointID': 4,
  'x': 481809.58159979654,
  'y': 3768635.463000134,
  'z': 390.0384000000049,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.03,
  'ZAccuracy': 0.1,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 36,
    'x': 1268.2839313062957,
    'y': -2184.747067550659,
    'u': 1366,
    'v': -2462,
    'score': -1},
   {'imageID': 37,
    'x': 1027.0852980913894,
    'y': -3252.3253712457463,
    'u': 1323.215406557291,
    'v': -3545.6171942309097,
    'score': 0.99},
   {'imageID': 35,
    'x': 1526.360031975339,
    'y': -1116.6758359674063,
    'u': 1402.7008106253338,
    'v': -1393.087023387884,
    'score': 0.99},
   {'imageID': 14,
    'x': 1185.6193340794375,
    'y': -2233.9349439400007,
    'u': 2237.095098322607,
    'v': -3347.371174508406,
    'score': 0.98},
   {'imageID': 13,
    'x': 2145.6347622651197,
    'y': -1608.1151436739951,
    'u': 2262.8774628470715,
    'v': -2236.9719395058187,
    'score': 0.98},
   {'imageID': 12,
    'x': 3199.6260111254423,
    'y': -1157.2364489676322,
    'u': 2309.2287243861506,
    'v': -1132.4082861465004,
    'score': 0.96}]},
 {'pointID': 5,
  'x': 481833.5885997999,
  'y': 3768652.399000132,
  'z': 391.8996000000043,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.019,
  'ZAccuracy': 0.075,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 15,
    'x': 2418.0250841583234,
    'y': -1953.4311420110448,
    'u': 2664,
    'v': -2159,
    'score': -1},
   {'imageID': 14,
    'x': 3386.639266379795,
    'y': -1345.7217982447933,
    'u': 2688.6442988563504,
    'v': -1017.2406513944115,
    'score': 0.99},
   {'imageID': 16,
    'x': 1460.259283558527,
    'y': -2607.0300817514762,
    'u': 2645.4857502152345,
    'v': -3317.507676670906,
    'score': 0.99},
   {'imageID': 33,
    'x': 1035.4524564902322,
    'y': -1131.9428663320778,
    'u': 928.1701610377334,
    'v': -1504.2000105207383,
    'score': 0.99},
   {'imageID': 34,
    'x': 773.61525667361,
    'y': -2199.4072315778544,
    'u': 900.5359967708275,
    'v': -2612.9262154289454,
    'score': 0.99},
   {'imageID': 133,
    'x': 2752.8717156406283,
    'y': -622.9684658683827,
    'u': 1545.3951032378961,
    'v': -1664.7099496229532,
    'score': 0.99},
   {'imageID': 154,
    'x': 2614.3841527053846,
    'y': -993.9301818128313,
    'u': 2064.2979989946184,
    'v': -1321.1693344066261,
    'score': 0.99},
   {'imageID': 155,
    'x': 1802.0396933064824,
    'y': -1776.2470404983242,
    'u': 2053.540448960158,
    'v': -2462.6466742677994,
    'score': 0.99},
   {'imageID': 132,
    'x': 4003.5485216855404,
    'y': -553.7062666965958,
    'u': 1568.6001378428437,
    'v': -460.1753512489395,
    'score': 0.9400000000000001},
   {'imageID': 9,
    'x': 4785.99405963059,
    'y': -1255.7155178294024,
    'u': 4846.348837318955,
    'v': -1556.6039056527325,
    'score': 0.92},
   {'imageID': 10,
    'x': 4850.620605680874,
    'y': -1849.0553435655372,
    'u': 4847.813814447198,
    'v': -1935.4850735500147,
    'score': 0.88},
   {'imageID': 8,
    'x': 4663.9418446262525,
    'y': -177.7122880972098,
    'u': 4845.388037882715,
    'v': -417.83384358345666,
    'score': 0.87}]},
 {'pointID': 6,
  'x': 481877.1809997994,
  'y': 3768656.118000134,
  'z': 391.11849999999686,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.026,
  'ZAccuracy': 0.085,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 8,
    'x': 2678.1471394781834,
    'y': -3178.3405353643534,
    'u': 2518,
    'v': -3162,
    'score': -1},
   {'imageID': 6,
    'x': 2453.401858902518,
    'y': -981.7382028942424,
    'u': 2527.6374585608273,
    'v': -960.408323748291,
    'score': 0.99},
   {'imageID': 7,
    'x': 2550.7043473355384,
    'y': -2084.0663451674686,
    'u': 2521.2156009929417,
    'v': -2060.41022796122,
    'score': 0.99},
   {'imageID': 127,
    'x': 3765.2378355487954,
    'y': -1060.591021741829,
    'u': 3234.378932717393,
    'v': -643.0335295556781,
    'score': 0.99},
   {'imageID': 128,
    'x': 3200.133012430143,
    'y': -2021.1905595910712,
    'u': 3234.9944940967976,
    'v': -1749.534537365656,
    'score': 0.99},
   {'imageID': 18,
    'x': 3244.5849036808436,
    'y': -4235.220959327178,
    'u': 4996.8257566994525,
    'v': -2804.3173133558857,
    'score': 0.98},
   {'imageID': 17,
    'x': 4182.305421676127,
    'y': -3581.954162991636,
    'u': 5007.886090590433,
    'v': -1676.1955924742128,
    'score': 0.98},
   {'imageID': 129,
    'x': 2628.62648325397,
    'y': -2994.4460019355056,
    'u': 3231.2361929611725,
    'v': -2889.7026416871468,
    'score': 0.98},
   {'imageID': 99,
    'x': 418.3359095070293,
    'y': -1258.512455151848,
    'u': 536.8479178556126,
    'v': -2747.829070232272,
    'score': 0.97},
   {'imageID': 97,
    'x': 1572.9153741448795,
    'y': 689.8633984565097,
    'u': 250.3873194214275,
    'v': -601.6875573906098,
    'score': 0.97},
   {'imageID': 130,
    'x': 2424.9451530233505,
    'y': -3201.7511822047863,
    'u': 3218.65500064441,
    'v': -3151.1246782633043,
    'score': 0.97},
   {'imageID': 98,
    'x': 996.0778225592353,
    'y': -328.3934104627872,
    'u': 445.8785902558211,
    'v': -1687.2434873189281,
    'score': 0.9500000000000001}]},
 {'pointID': 7,
  'GCPType': 3,
  'x': 481870.239099797,
  'y': 3768697.345000133,
  'z': 392.0460000000021,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.017,
  'ZAccuracy': 0.057,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 28,
    'x': 1538.1866750358733,
    'y': -532.2370264981157,
    'u': 1360,
    'v': -724,
    'score': -1},
   {'imageID': 18,
    'x': 3303.875228233192,
    'y': -768.3871628326776,
    'u': 2204.089815715067,
    'v': -749.3008528279952,
    'score': 0.99},
   {'imageID': 19,
    'x': 2365.864701677895,
    'y': -1398.7706156600475,
    'u': 2174.9028798506024,
    'v': -1875.984650512448,
    'score': 0.99},
   {'imageID': 20,
    'x': 1423.9438617056176,
    'y': -2037.8363183445567,
    'u': 2146.943203844172,
    'v': -3015.0208057448117,
    'score': 0.99},
   {'imageID': 29,
    'x': 1415.465190989917,
    'y': -1565.4427168938614,
    'u': 1390.556308290631,
    'v': -1809.2871531213962,
    'score': 0.99},
   {'imageID': 30,
    'x': 1182.815799112063,
    'y': -2646.03974793903,
    'u': 1374.543890308117,
    'v': -2934.8902375409434,
    'score': 0.98},
   {'imageID': 100,
    'x': 2970.4269192841457,
    'y': -869.275060072224,
    'u': 2366.112003801152,
    'v': -912.8527404831867,
    'score': 0.98},
   {'imageID': 101,
    'x': 2378.4370989657855,
    'y': -1836.1467058191108,
    'u': 2453.1727128485363,
    'v': -2042.4632373207112,
    'score': 0.98},
   {'imageID': 125,
    'x': 1797.7822354522564,
    'y': -461.24989516649566,
    'u': 1219.0727580380988,
    'v': -1163.59270883112,
    'score': 0.98},
   {'imageID': 127,
    'x': 581.4692090616384,
    'y': -2457.9332063376173,
    'u': 1203.146298599865,
    'v': -3464.919920453623,
    'score': 0.98},
   {'imageID': 126,
    'x': 1180.8929758546792,
    'y': -1463.0537124768982,
    'u': 1215.2125091841476,
    'v': -2308.725427615229,
    'score': 0.97},
   {'imageID': 111,
    'x': 2562.41950057302,
    'y': -4422.360369750497,
    'u': 5325.7548548713785,
    'v': -1550.3587625055732,
    'score': 0.96}]},
 {'pointID': 8,
  'x': 481870.2799997963,
  'y': 3768711.0830001337,
  'z': 392.008799999996,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.022,
  'ZAccuracy': 0.065,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 28,
    'x': 2224.5482001503,
    'y': -1410.6931195041589,
    'u': 2169,
    'v': -1491,
    'score': -1},
   {'imageID': 19,
    'x': 2570.9740481848366,
    'y': -281.7718154562792,
    'u': 1387.271539832649,
    'v': -1057.8279251639256,
    'score': 0.99},
   {'imageID': 21,
    'x': 693.147648464457,
    'y': -1563.572538288433,
    'u': 1342.9820013322922,
    'v': -3339.9633787960774,
    'score': 0.99},
   {'imageID': 27,
    'x': 2260.964213302588,
    'y': -309.1966031507521,
    'u': 2100.167840676639,
    'v': -369.32043410199026,
    'score': 0.99},
   {'imageID': 29,
    'x': 2060.453166930871,
    'y': -2495.214747320475,
    'u': 2193.565037578466,
    'v': -2606.5678936708973,
    'score': 0.99},
   {'imageID': 101,
    'x': 3484.067399331662,
    'y': -1584.9498085535604,
    'u': 3203.45278307227,
    'v': -1192.4095288676094,
    'score': 0.99},
   {'imageID': 102,
    'x': 2894.537529903129,
    'y': -2533.4518470451117,
    'u': 3275.2516434249856,
    'v': -2311.3464277854155,
    'score': 0.99},
   {'imageID': 100,
    'x': 4057.7708347976377,
    'y': -617.0173488430285,
    'u': 3098.83972432079,
    'v': -70.79692523882477,
    'score': 0.98},
   {'imageID': 126,
    'x': 55.79641124983186,
    'y': -1742.8786131393024,
    'u': 391.4424661890039,
    'v': -3124.535544674511,
    'score': 0.98},
   {'imageID': 111,
    'x': 1881.2836954756194,
    'y': -3455.1100803323166,
    'u': 4488.993258816745,
    'v': -2386.6259862486836,
    'score': 0.96},
   {'imageID': 110,
    'x': 2720.304067817282,
    'y': -3644.208236697469,
    'u': 4459.18444435851,
    'v': -1236.880377919454,
    'score': 0.9400000000000001},
   {'imageID': 109,
    'x': 3224.548137080206,
    'y': -4218.050693789353,
    'u': 4503.529478939508,
    'v': -136.15927014399608,
    'score': 0.91}]},
 {'pointID': 9,
  'x': 481856.2016997986,
  'y': 3768735.4040001323,
  'z': 391.54580000000715,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.012,
  'ZAccuracy': 0.036,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 102,
    'x': 3967.922273311432,
    'y': -1910.5198602825926,
    'u': 3792,
    'v': -1183,
    'score': -1}]},
 {'pointID': 10,
  'x': 481774.75349979725,
  'y': 3768735.5910001313,
  'z': 390.3497000000061,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.018,
  'ZAccuracy': 0.056,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 87,
    'x': 1321.8575929813637,
    'y': -3236.8032573789524,
    'u': 1388,
    'v': -3300,
    'score': -1},
   {'imageID': 83,
    'x': 3569.616795765037,
    'y': -1494.3320318996007,
    'u': 2556.9934811451467,
    'v': -944.7332936793616,
    'score': 0.65}]},
 {'pointID': 11,
  'GCPType': 3,
  'x': 481812.891599796,
  'y': 3768653.304000132,
  'z': 392.92399999999907,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.023,
  'ZAccuracy': 0.094,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 35,
    'x': 1976.4116320168541,
    'y': -2464.8323745503894,
    'u': 2132,
    'v': -2613,
    'score': -1},
   {'imageID': 13,
    'x': 2847.3139141691418,
    'y': -250.32135806002134,
    'u': 1410.1843346930605,
    'v': -968.5648745500408,
    'score': 0.98},
   {'imageID': 14,
    'x': 1716.5514575133548,
    'y': -852.1743221855204,
    'u': 1366.2438813439244,
    'v': -2150.3884540502904,
    'score': 0.98},
   {'imageID': 34,
    'x': 2251.6475716712107,
    'y': -1358.731714836184,
    'u': 2162.9436478649022,
    'v': -1473.7877506440202,
    'score': 0.98},
   {'imageID': 154,
    'x': 2534.8905827941344,
    'y': -2748.6852536726774,
    'u': 3246.215131216167,
    'v': -2620.608862017182,
    'score': 0.98}]},
 {'pointID': 12,
  'x': 481774.7307998004,
  'y': 3768681.6010001306,
  'z': 392.5825000000041,
  'spatialReference': {'wkid': 26911,
   'latestWkid': 26911,
   'vcsWkid': 5773,
   'latestVcsWkid': 5773},
  'xyAccuracy': 0.017,
  'ZAccuracy': 0.051,
  'imagePointSpatialReference': {'ics': '', 'topup': True},
  'imagePoints': [{'imageID': 68,
    'x': 2346.5660120900134,
    'y': -1260.0998777410398,
    'u': 2080,
    'v': -1626,
    'score': -1},
   {'imageID': 51,
    'x': 2868.2955086511065,
    'y': -317.28676089739383,
    'u': 1558.007630335989,
    'v': -874.9177238001142,
    'score': 0.99},
   {'imageID': 69,
    'x': 1668.7419406381914,
    'y': -2132.38128377689,
    'u': 2116.6180844424534,
    'v': -2745.6502795498513,
    'score': 0.99},
   {'imageID': 67,
    'x': 2952.557333873551,
    'y': -356.13292316410616,
    'u': 2034.2269673108822,
    'v': -516.4125131234646,
    'score': 0.99},
   {'imageID': 52,
    'x': 1922.5629017456142,
    'y': -960.4322062886504,
    'u': 1565.2971407800487,
    'v': -2014.2030668122463,
    'score': 0.99},
   {'imageID': 149,
    'x': 4189.2879294000195,
    'y': -1844.3844015527663,
    'u': 3779.830028456768,
    'v': -811.9145931032474,
    'score': 0.99},
   {'imageID': 150,
    'x': 3408.7203170466587,
    'y': -2675.8012101359936,
    'u': 3813.7695372948847,
    'v': -1953.7953767346203,
    'score': 0.99},
   {'imageID': 163,
    'x': 3066.4762281089297,
    'y': -2907.8873383498985,
    'u': 3858.4416715718116,
    'v': -1667.1605281276538,
    'score': 0.99},
   {'imageID': 164,
    'x': 1971.7933699060768,
    'y': -3154.3531426850163,
    'u': 3903.5988751330124,
    'v': -2818.4755732468484,
    'score': 0.99}]}]

3.2.3 Update Control Points Feature Class

Next, we will append the control point sets to the image collection’s control point feature class using edit_control_points().

mission.edit_control_points(control_points= control_point_sets)

3.3 Redo Block Adjustment

After adding the ground control point sets to the image collection's control point table with steps above, we can rerun compute sensor model to refine block adjustment result.

Here, mode='Refine' represents to adjust the image at 1x of the source imagery resolution.

mission.compute_sensor_model(
                mode="Refine", 
                location_accuracy="High"
)
mission.generate_report(report_format="HTML")

Step 4: Get Results

The final step after block adjustment is to generate products. The reconstruct_surface() method can generate one or multiple reality mapping products- DSM, DTM, true ortho, Mesh and point clouds from adjusted imagery.

%%time
products_2d = mission.reconstruct_surface(
                        output_products= ["DSM", "TRUE_ORTHO", "DTM", "POINT_CLOUD", "MESH"],
                        quality= "High"
                        )
products_2d.True_Ortho.layers[0]
<ImageryLayer url:"https://realitytest.esri.com/server/rest/services/Hosted/DroneTrueOrtho/ImageServer">

Conclusion

You've successfully completed a reality mapping workflow for drone imagery using the ArcGIS API for Python. In this tutorial, you:

  • Created a reality mapping project and mission for drone imagery.
  • Performed block adjustment to geometrically correct your imagery collection.
  • Refined the adjustment using GCPs for improved absolute accuracy.
  • Generated DSM, DTM, true ortho, point clouds and mesh products.

The same principles and methods demonstrated here can be adapted for:

This is a versatile approach for reality mapping across different platforms and scales.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.