User Tools

Site Tools


guides:ai

Running AI Models in Developer Kernel (Experimental)

Documentation | Tutorials | Running AI Models in Developer Kernel (Experimental)

This tutorial explains how to run Python-driven AI models on TatukGIS Viewer snapshots and raster layers.

Status (read this first):

  • This feature is experimental and work in progress.
  • Currently supported only in DK.Delphi (RAD Studio / Delphi). .NET support coming soon.
  • Requires the Python4Delphi package.
  • Provided Sample - AIModelRunner - is an FMX sample.
  • Report bugs and suggestions to support@tatukgis.com or directly to stanislaw.kosinski@tatukgis.com.

1. Introduction

TatukGIS AI runs inference through Python scripts.

What TatukGIS AI Model Runner Is:

  • A runner/bridge to execute Python scripts directly from TatukGIS.
  • An automated pipeline that exports a Viewer snapshot or layer to an image file.
  • A parser that converts a JSON returned by the Python script into TatukGIS results (e.g., layers, polygons).

What TatukGIS AI Model Runner Is Not:

  • A proprietary AI engine or custom AI model.
  • A tool that executes AI directly on the Viewer without a Python intermediary.

Supported inputs

A Viewer snapshot can contain content from multiple layers, but it is less precise than a single layer input. Exporting an image with pixel-perfect precision is difficult when combining multiple layers with different dimensions.

An exported TGIS_LayerPixel maintains single-pixel precision. An imported layer with AI model postprocessing will align perfectly within the project.

Supported outputs (as implemented by GisAIModelOutput)

  • Layer: file-backed layer reference (pixel/vector automatically assigned)
  • Detection: bbox/polygon detections converted to vector polygon layers
  • Logs: strings containing info
  • Raw: fallback / unknown output, optionally capturing stdout/stderr

2. Prerequisites

2.1 Installing Python

Install a Python 3.x runtime and make sure it is usable on the machine where the application runs. The sample and all predefined models were tested on Python 3.9 and that is the version I would recommend for running the sample.

You do not need to install required Python modules manually via pip. The TatukGIS AI feature allows you to specify the required modules for a given script. The system will automatically install these dependencies before executing the Python environment.

2.2 Installing Python4Delphi

Install Python4Delphi in RAD Studio via GetIt or manual installation.

You must end up with:

  • Python4Delphi units available for compilation.
  • A working runtime initialization (Python DLL path correctly resolved).

Verification step: Upon installing Python4Delphi, you will find several included demos. Run one of these demos to verify that Python4Delphi correctly locates and uses the Python distribution on your machine. If Python initialization fails in the demo, the TatukGIS AI feature will not run. Resolve environmental issues before proceeding.

2.3 Compiling sources with the Python4Delphi define

TatukGIS AI integration requires conditional compilation. After installing Python4Delphi extension, enable the Python4Delphi define in your project settings:

  • Project Options → Delphi Compiler → Conditional defines

Use the following define:

  • GIS_PYTHON4DELPHI

Without this define, Python-backed AI classes will not work.

2.3.1 DK.Delphi Binary Version

If you are using DK.Delphi Binary Version (installed through installer, not SourceCodeManager), having sources for GisAIPython.pas class is essential to run the SDK with the GIS_PYTHON4DELPHI define.

In latest version (DK 112) we have added the necessary source file to installation - it is located in $(DK_SRC)\Source. This path has been added to Rad Studio configuration (Library Paths) as well.

As a result, you may enable the define both in project settings, but also globally through adding:

{$DEFINE GIS_PYTHON4DELPHI}

to $(DK_SRC)\Source\GisAIPython.pas file.

2.3.2 DK.Delphi SourceCodeManager version

If you are using DK.Delphi SourceCodeManager version, DK sources are recompiled when building the project. As so, adding the define to project options is enough.

But of course, you may also enable the define globally through adding:

{$DEFINE GIS_PYTHON4DELPHI}

to $(DK_SRC)\Source\GisAIPython.pas file.


3. AIModelRunner Sample

Start with the AIModelRunner sample to validate the full pipeline.

The sample uses following command to download SampleData (models, config files, example images) onto your PC:

TGIS_Utils.GisSamplesDataDirDownload('AI.1')

It's around 200mb of data and it may take a moment to download the data.

I would recommend Python 3.9 to use with the sample. You may define which Python DLL should be used with following command:

PythonWorker.Python.SetPythonDllPath()

3.1 Running Upscaling sample using Real-ESRGAN model

The sample includes a pre-configured setup for Real-ESRGAN, an AI model used for image resolution upscaling. This requires no additional configuration.

Validation steps:

  • Load a small raster extent in the Viewer.
  • Zoom in on the object you want to upscale. The sample only upscales the VisibleExtent.
  • Run the Real-ESRGAN AI action on the Viewer/Layer input.
  • Confirm that:
    • Python starts successfully.
    • Required modules install automatically.
    • The output raster is produced and georeferencing is preserved (the final image is located correctly on the map).

If this step fails, investigate your Python/Python4Delphi environment setup. Do not attempt custom models yet.

3.2 Running object detection sample using MMRotate model

The sample may also be used with an MMRotate model, an AI model used for oriented object detection. Unlike Real-ESRGAN, this model requires additional config files. They are included in SampleData downloaded through TGIS_Utils.GisSamplesDataDirDownload('AI.1').

MMRotate wrapper will create a vector layer for each object category it detected and will add it to Viewer.

Validation steps:

  • Load a small raster extent in the Viewer.
  • Zoom to the area you want to analyze. The sample runs detection only on the exported VisibleExtent.
  • Run the MMRotate model on the Viewer/Layer input.
  • Confirm that:
    • Python starts successfully.
    • Required Python modules are available.
    • The model loads without errors.
    • Detection results are returned.
    • Output vector layer or layers are created correctly.
    • Detection geometry is placed correctly on the map.

If this step fails, first investigate your Python/Python4Delphi environment setup. Make sure that all required model files, config files, and Python package dependencies are present and compatible before troubleshooting the TatukGIS integration itself.

3.3 Running Custom Models via the Sample

Once predefined models work, you can use the AIModelRunner sample interface to load a custom model. You will need to provide the model file, the Python script, and specify the necessary dependencies. The steps for structuring custom models are detailed below.


4. Running Custom Models

Custom models are driven by TGIS_AIModelCustom (unit GisAIModelCustom). You must provide:

  • A model file path.
  • A list of required Python modules (for automatic installation).
  • A Python script template that performs inference and prints a JSON manifest consumed by TGIS_AIModelOutput.

4.1 Model File Formats

While the system defaults to looking for .onnx or .pt (PyTorch) extensions, the model file can be in any format. TatukGIS does not strictly enforce the extension; the provided Python script is solely responsible for loading and executing the model correctly.

4.2 Tutorial: Adapting External Models (e.g., Ultralytics YOLO)

This tutorial demonstrates the structural requirements for adapting an external model to the TatukGIS JSON contract. Ultralytics YOLO OBB (Oriented Bounding Box) is used as the conceptual example.

Third-party licensing notice (Ultralytics example): Ultralytics YOLO, the ultralytics Python package, model weights, and related documentation are third-party materials and are not part of any TatukGIS product, license, source code, or distribution. This section is provided solely to demonstrate how a third-party model may be adapted to interoperate with TatukGIS software through a Python script. TatukGIS does not grant, transfer, sublicense, or imply any rights to use Ultralytics software, models, trademarks, or documentation.

Use of Ultralytics software and models is governed exclusively by Ultralytics' own license terms, which may change over time. Personal, research, or open-source use may be available under Ultralytics' published terms. Proprietary or closed-source commercial use may require obtaining an appropriate license directly from Ultralytics. Before any internal, customer-facing, or commercial deployment, review the current terms on the official Ultralytics pages:
* Ultralytics licensing page
* Ultralytics plans / commercial licensing page

This documentation is technical guidance only and is not legal advice. You are responsible for verifying third-party licensing obligations before use or distribution.

Step 1: Define Required Modules

Configure TatukGIS to install the necessary packages required by the vendor's model. For a YOLO model, you would specify: ['ultralytics', 'numpy']

Step 2: Provide the Model File

Acquire the model file. For Ultralytics, download a pre-trained OBB model (e.g., yolo11n-obb.pt) from the Ultralytics GitHub repository or train your own custom weights. Pass this absolute path to the TatukGIS wrapper.

Step 3: Build the Python Script Wrapper

Due to licensing compliance, you must write the model execution code yourself using the vendor's documentation. For the specific inference code required to load the model and extract bounding boxes, refer to the Ultralytics OBB documentation.

The script below provides the required wrapper. It shows how to capture the input paths from TatukGIS and how to structure the final JSON output.

TatukGIS replaces the placeholders («MODEL_PATH» and «IMAGE_PATH») with single-quoted absolute paths at runtime.

import json
# Import chosen third-party AI libraries here (e.g., ultralytics, numpy)
 
# TatukGIS runtime parameters injected automatically
MODEL_PATH = r<<MODEL_PATH>>
IMAGE_PATH = r<<IMAGE_PATH>>
 
def run_inference():
    # -----------------------------------------------------------------
    # 1. LOAD MODEL AND RUN INFERENCE
    # -----------------------------------------------------------------
    # Example conceptual flow:
    # model = load_vendor_model(MODEL_PATH)
    # results = model(IMAGE_PATH)
 
    # -----------------------------------------------------------------
    # 2. POSTPROCESS INTO TATUKGIS JSON CONTRACT
    # -----------------------------------------------------------------
    detections = []
 
    # Example mapping logic for Oriented Bounding Box
    # for result in results:
    #     for obb in result.extracted_bounding_boxes:
    #         detections.append({
    #             "LabelText": str(obb.class_name),
    #             "ClassId": int(obb.class_id),
    #             "Score": float(obb.confidence),
    #             "GeomKind": "Polygon",
    #             "Polygon": obb.points.tolist() # Format: [[x,y], [x,y], ...]
    #         })
 
    # Example fallback dimensions
    img_h, img_w = 0, 0 
 
    manifest = {
        "Version": 1,
        "Items": [
            {
                "SourceType": "Detection",
                "CoordSpace": "Image",
                "ImageWidth": int(img_w),
                "ImageHeight": int(img_h),
                "Detections": detections
            }
        ]
    }
 
    # Output must be printed to stdout for TatukGIS to parse
    print(json.dumps(manifest, ensure_ascii=False))
 
if __name__ == "__main__":
    run_inference()

4.3 Script Output Contract (JSON)

The TGIS_AIModelOutput.ParseJson() method expects a root JSON object containing an array of items.

Root Structure

Property Type Requirement Description
Version Integer Optional Contract version (defaults to 1).
Items Array Required Array of output item objects.

Item Definitions by SourceType

1. SourceType: “Layer” (Loads a file-backed vector or raster layer)

Property Type Requirement Description
Path String Required Absolute path to the file on disk.
Title String Optional Layer name in the Viewer.

2. SourceType: “Detection” (Generates vector polygon layers from bounding boxes/polygons)

Property Type Requirement Description
Detections Array Required Array of Detection Objects (see below).
CoordSpace String Optional “Image” (pixels, top-left origin) or “Map” (map units).
ImageWidth Integer Optional Width of the source image.
ImageHeight Integer Optional Height of the source image.

Detection Object Structure:

Property Type Requirement Description
GeomKind String Required “BBox” or “Polygon”.
LabelText String Optional Classification label.
ClassId Integer Optional Classification ID.
Score Float Optional Confidence score.
BBoxXMin, BBoxYMin, BBoxXMax, BBoxYMax Float Conditional Required if GeomKind is “BBox”.
Polygon Array Conditional Required if GeomKind is “Polygon”. Format: [[x,y], [x,y], ...].

3. SourceType: “Logs” (Outputs processing logs)

Property Type Requirement Description
Messages Array Required Array of string messages.

4. SourceType: “Raw” (Fallback container for unparsed standard output)

Property Type Requirement Description
StdOut String Optional Captured standard output.
StdErr String Optional Captured standard error.

Example JSON Manifest

{
  "Version": 1,
  "Items": [
    {
      "SourceType": "Layer",
      "Path": "C:\\temp\\output_raster.tif",
      "Title": "Processed Raster"
    },
    {
      "SourceType": "Detection",
      "CoordSpace": "Image",
      "ImageWidth": 1024,
      "ImageHeight": 1024,
      "Detections": [
        {
          "GeomKind": "BBox",
          "LabelText": "Vehicle",
          "ClassId": 2,
          "Score": 0.95,
          "BBoxXMin": 150.0,
          "BBoxYMin": 200.0,
          "BBoxXMax": 350.0,
          "BBoxYMax": 400.0
        },
        {
          "GeomKind": "Polygon",
          "LabelText": "Structure",
          "ClassId": 5,
          "Score": 0.88,
          "Polygon": [[10, 10], [50, 10], [50, 50], [10, 50]]
        }
      ]
    }
  ]
}

4.4 Running Custom Models Programmatically (Without UI)

To execute custom models in a background process or non-GUI application, bypass the UI components and interact directly with the core AI classes.

Execution Steps

Step Action Relevant Method / Class
1 Initialize Python runtime TGIS_AIPythonManager.Create and .Initialize
2 Instantiate the model TGIS_AIModelCustom.Create()
3 Export map state to image TGIS_ImageExporter.ExportToImage()
4 Verify dependencies Model.InstallModules()
5 Run inference Model.Run()
6 Retrieve results GetDetections(), GetDetectionLayers(), and GetLayers()

Code Example

procedure RunModelHeadless(const LayerPix: TGIS_LayerPixel; const Viewer: TGIS_ViewerWnd);
var
  PythonManager: TGIS_AIPythonManager;
  Model: TGIS_AIModelCustom;
  RequiredModules: TArray<string>;
  ScriptText: string;
  ImagePath: string;
  AlignedExtent: TGIS_Extent;
  Dx, Dy: Double;
  RawDetections: TArray<TGIS_AIDetection>;
  Detection: TGIS_AIDetection;
  DetectionLayers: TObjectList<TGIS_LayerVector>;
  DetectionLayer: TGIS_LayerVector;
  LayerItem: TGIS_LayerAbstract;
begin
  // 1. Initialize Python runtime
  PythonManager := TGIS_AIPythonManager.Create;
  try
    if not PythonManager.Initialize then
      raise Exception.Create('Python initialization failed.');
 
    // 2. Instantiate the model
    SetLength(RequiredModules, 1);
    RequiredModules[0] := 'numpy'; 
    ScriptText := TFile.ReadAllText('C:\Path\To\script.py');
 
    Model := TGIS_AIModelCustom.Create(
      'HeadlessModel',
      PythonManager,
      'C:\Path\To\model.pt',
      ScriptText,
      RequiredModules
    );
 
    try
      // 3. Export map state to image
      ImagePath := TGIS_ImageExporter.ExportToImage(LayerPix, Viewer.VisibleExtent, AlignedExtent);
 
      try
        // 4. Verify dependencies
        Model.InstallModules;
 
        // 5. Run inference
        if Model.Run(ImagePath) then
        begin
          // GetPixelSize determines how a single pixel from the output image translates
          // to distance in the map extent. This is required to properly map outputs.
          TGIS_ImageExporter.GetPixelSize(LayerPix, Dx, Dy);
 
          // 6a. Retrieve raw detections for manual processing
          RawDetections := Model.LastResult.GetDetections;
          for Detection in RawDetections do
          begin
            // Map the detection to a given layer or process geometry manually
            // e.g., read Detection.GeomKind, Detection.Polygon, or Detection.LabelText
          end;
 
          // 6b. Retrieve pre-built detection layers
          DetectionLayers := Model.LastResult.GetDetectionLayers(AlignedExtent, Dx, Dy);
          if Assigned(DetectionLayers) then
          begin
            for DetectionLayer in DetectionLayers do
              Viewer.Add(DetectionLayer);
          end;
 
          // 6c. Retrieve and render standard layers
          for LayerItem in Model.LastResult.GetLayers() do
          begin
            if LayerItem is TGIS_LayerVector then
              (LayerItem as TGIS_LayerVector).Extent := AlignedExtent
            else if LayerItem is TGIS_LayerPixel then
              (LayerItem as TGIS_LayerPixel).Extent := AlignedExtent;
 
            Viewer.Add(LayerItem);
          end;
        end;
      finally
        if FileExists(ImagePath) then
          TFile.Delete(ImagePath);
      end;
    finally
      Model.Free;
    end;
  finally
    PythonManager.Free;
  end;
end;
2026/03/27 13:28

Page Tools