Skip to content

A Nix Flake configuration for building Orfeo Toolbox (OTB)

License

Notifications You must be signed in to change notification settings

daspk04/otb-nix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

otb-nix

This repo contains Nix Flake configuration for building Orfeo Toolbox from source with remote modules.

Note for Users:
The Orfeo Toolbox (OTB) nix package is now available directly in nixpkgs, suitable for standard installations. However, if you require advanced compilation or use of additional remote modules not included by default, the configuration provided in this repo is recommended.

How to use OTB nix package

NB: Assuming that one has already Nix with Flake enabled. Check guide

  1. First create a directory locally mkdir otb
  2. Then inside the directory create a flake.nix file and copy the content as mentioned below
{
  description = "A flake for Orfeo Toolbox";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
    flake-utils.url = "github:numtide/flake-utils";
    otbpkgs.url = "github:daspk04/otb-nix";
  };

  outputs = {
    self,
    nixpkgs,
    flake-utils,
    otbpkgs,
  }:
    flake-utils.lib.eachDefaultSystem (
      system: let
        pkgs = import nixpkgs {inherit system;};
        otb = otbpkgs.packages.${system}.otb;
        python = pkgs.python312;
        pyPkgs = python.pkgs;
      in {
        devShells.default = pkgs.mkShell rec {
          packages = with pkgs; [
            otb
            bashInteractive
            pyPkgs.python
            pyPkgs.venvShellHook
          ];
          venvDir = "./.venv";

          otbPath = with pkgs; pkgs.lib.makeLibraryPath [otb];
            
          # add the python path to be able to use otb via python
          postShellHook = ''
            export PYTHONPATH="$PYTHONPATH:${otbPath}/otb/python"
          '';
        };
      }
    );
}
  1. Then run nix develop, this should create a nix shell with python virtual environment (.venv) with otb and python 3.12 enabled.
  2. Now one should be able to use all the command line and python api as mentioned in documentation.

Optional: Step 3 will not be needed if nix-direnv is used, it should automatically activate the shell environment when one enters the directory. Incase one has already installed nix-direnv then just copy the .envrc file in this repo and put it inside the above folder.

Advantage of OTB with Nix

  • This is highly modular and allows one to customize and build OTB with a different version of packages as per need such as GDAL, ITK, etc. as Nix already has a lot of packages.
  • Building with Nix is almost reproducible.
  • One can easliy combine OTB with different remote modules with minimal configuration options.
  • This was build out of my requirement, as the current OTB build against GDAL does not support Geo(Parquet) and Blosc compressor for Zarr dataset. c.f. So this Nix pacakge solves those issues as GDAL on Nixpkgs already has Geo(Parquet) and Blosc.
  • One can combine OTB with different geospatial python libraries such as rasterio, geopandas etc. which as already available with Nixpkgs no need to create a separate environment.
  • There isn't any conda package for OTB, although it is under plan; this Nixpkgs should help people who want to use OTB with a different python version or packages such as (gdal,rasterio, geopandas etc.), which should solve most of those use cases for OTB to be imported in an custom python environment.
  • One can also build a multi-arch version of OTB package apart from AMD64 (x86_64-linux) i.e. ARM64 (aarch64-linux) as currently OTB has no aarch64-linux version.
  • One can easily build docker image as well.

Advanced Configuration

  1. Python Environment: OTB + Pyotb + GDAL + Rasterio. Here is an example of how to create an flake.nix with all the above python packages. Pyotb is not available in Nixpkgs so we will build it from the source with Nix.
{
  description = "A flake for Orfeo Toolbox";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    otbpkgs.url = "github:daspk04/otb-nix";
  };

  outputs = {
    self,
    nixpkgs,
    nixpkgs-unstable,
    flake-utils,
    otbpkgs,
  }:
    flake-utils.lib.eachDefaultSystem (
      system: let
        pkgs = import nixpkgs {inherit system;};
        otb = otbpkgs.packages.${system}.otb;
        python = pkgs.python312;
        pyPkgs = python.pkgs;
        
        pyotb = pyPkgs.buildPythonPackage rec {
          pname = "pyotb";
          version = "2.1.0";
          pyproject = "true";

          src = pkgs.fetchFromGitHub {
            owner = "orfeotoolbox";
            repo = "pyotb";
            tag = version;
            hash = "sha256-KomIMVx4jfsTSbGtoml9ON/82sHanOkp/mp1TiUaa2E=";
          };
        
          build-system = [
            setuptools
          ];
        
          propagatedBuildInputs = [
            numpy
          ];
        
          nativeCheckInputs = [
            pytestCheckHook
            pytest-cov
            requests
          ];
        };
      in {
        devShells.default = pkgs.mkShell rec {
          packages = with pkgs; [
            bashInteractive
            pyPkgs.gdal
            pypkgs.rasterio
            pyPkgs.python
            pyPkgs.venvShellHook
            pyotb
            otb
          ];
          venvDir = "./.venv";

          otbPath = with pkgs; pkgs.lib.makeLibraryPath [otb];

          postShellHook = ''
            export PYTHONPATH="$PYTHONPATH:${otbPath}/otb/python"
          '';
        };
      }
    );
}

Docker

  • Docker Image for OTB:
    • Linux AMD64
    • Linux ARM64: To build OTB for linux-aarch-64 there are 3 options:
      • The easiest way would be to build natively with ARM64
      • Compile using an emulator (Tested with GitHub Action and it builds fine)
      • We can also via nix cross compiler (Still needs to be Tested)
  1. One can build a docker image for OTB with python support and no remote modules (default).
1) Clone this repo
2) make build_docker
2) docker run -it --rm otb
  1. One can build a docker image for OTB with python support and all the remote modules.
1) Clone this repo
2) make build_dev_docker
2) docker run -it --rm otb-dev

Example 1:

Build a docker image based on OTB, pyotb, gdal and rasterio without cloning this repo.
  1. Create a local directory
  2. Create a flake.nix as shown below which already has the required python packages and as it points to this github directory so we don't need to clone.
  3. Copy the contents in docker.nix file and put it in the local directory.

Local directory should basically contain 2 files (optional copy the Makefile):

flake.nix
docker.nix
  1. Run command as mentioned below:
1) nix run .\#otb-docker.copyToDockerDaemon
2) docker run -it --rm otb

Example of flake.nix with OTB, Gdal, Pyotb and Rasterio:

{
  description = "A flake for Orfeo Toolbox";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    otbpkgs.url = "github:daspk04/otb-nix";
    nix2container.url = "github:nlewo/nix2container";
  };

  outputs = {
    self,
    nixpkgs,
    nixpkgs-unstable,
    nix2container,
    flake-utils,
    otbpkgs,
  }:
    flake-utils.lib.eachDefaultSystem (
      system: let
        pkgs = import nixpkgs {inherit system;};
        nix2containerPkgs = nix2container.packages.${system};
        python = pkgs.python312;
        pyPkgs = python.pkgs;
        otb = otbpkgs.packages.${system}.otb.override {
          python3 = python;
          enablePython = true;
        };

        otbPath = with pkgs; pkgs.lib.makeLibraryPath [otb];

        pyotb = pyPkgs.buildPythonPackage rec {
          pname = "pyotb";
          version = "2.1.0";
          pyproject = "true";

          src = pkgs.fetchFromGitHub {
            owner = "orfeotoolbox";
            repo = "pyotb";
            tag = version;
            hash = "sha256-KomIMVx4jfsTSbGtoml9ON/82sHanOkp/mp1TiUaa2E=";
          };
        
          build-system = [
            setuptools
          ];
        
          propagatedBuildInputs = [
            numpy
          ];
        
          nativeCheckInputs = [
            pytestCheckHook
            pytest-cov
            requests
          ];
        };
      in rec {
        packages = {
          otb-docker = pkgs.callPackage ./docker.nix {
            inherit pkgs otb nix2containerPkgs;
            img-name = "otb";
            img-tag = "latest";
            python3 = python;
            extra-python-packages = with pyPkgs; [pyotb gdal rasterio];
          };
        };
        devShells.default = pkgs.mkShell rec {
          packages = with pkgs; [
            bashInteractive
            pyPkgs.gdal
            pypkgs.rasterio
            pyPkgs.python
            pyPkgs.venvShellHook
            pyotb
            otb
          ];
          venvDir = "./.venv";

          postShellHook = ''
            export PYTHONPATH="$PYTHONPATH:${otbPath}/otb/python"
          '';
        };
      }
    );
}

Example2:

Build a docker image based on OTB, pyotb, gdal and rasterio without cloning this repo and some specific remote modules

  1. The steps and the command are same as Example1 except we just change the flake.nix file and the otb section for only remote modules.

Example of flake.nix with only activated remote modules such as prefetch and otbtf note on OTBTF

{
  description = "A flake for Orfeo Toolbox";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    otbpkgs.url = "github:daspk04/otb-nix";
    nix2container.url = "github:nlewo/nix2container";
  };

  outputs = {
    self,
    nixpkgs,
    nixpkgs-unstable,
    nix2container,
    flake-utils,
    otbpkgs,
  }:
    flake-utils.lib.eachDefaultSystem (
      system: let
        pkgs = import nixpkgs {inherit system;};
        nix2containerPkgs = nix2container.packages.${system};
        python = pkgs.python312;
        pyPkgs = python.pkgs;
        
        ## we only enable Prefetch and Otbtf remote modules
        otb = pkgs.callPackage ./pkgs/otb/. {
            inherit system;
            itk_4_13 = packages.itk_4_13;
            gdal = gdal;
            python3 = python; # build otb with fixed python version
            enablePython = true;
            enablePrefetch = true;
            enableOtbtf = true;
          };

        otbPath = with pkgs; pkgs.lib.makeLibraryPath [otb];

        pyotb = pyPkgs.buildPythonPackage rec {
          pname = "pyotb";
          version = "2.1.0";
          pyproject = "true";

          src = pkgs.fetchFromGitHub {
            owner = "orfeotoolbox";
            repo = "pyotb";
            tag = version;
            hash = "sha256-KomIMVx4jfsTSbGtoml9ON/82sHanOkp/mp1TiUaa2E=";
          };
        
          build-system = [
            setuptools
          ];
        
          propagatedBuildInputs = [
            numpy
          ];
        
          nativeCheckInputs = [
            pytestCheckHook
            pytest-cov
            requests
          ];
        };
      in rec {
        packages = {
          otb-docker = pkgs.callPackage ./docker.nix {
            inherit pkgs otb nix2containerPkgs;
            img-name = "otb";
            img-tag = "latest";
            python3 = python;
            extra-python-packages = with pyPkgs; [pyotb gdal rasterio];
          };
        };
        devShells.default = pkgs.mkShell rec {
          packages = with pkgs; [
            bashInteractive
            pyPkgs.gdal
            pypkgs.rasterio
            pyPkgs.python
            pyPkgs.venvShellHook
            pyotb
            otb
          ];
          venvDir = "./.venv";

          postShellHook = ''
            export PYTHONPATH="$PYTHONPATH:${otbPath}/otb/python"
          '';
        };
      }
    );
}

Develop

  • In case one needs to develop or experiment then
  • Clone this repo and make changes and push to your repository
  • Then in the above flake change the otbpkgs.url to point to the updated repo url.
otbpkgs.url = "github:{userName}/{repoName}?ref={branchName}";

How to build OTB locally

1) clone this repo
2) nix build #.otb 
or # nix build #.otb-all --> this will build OTB with all the remote modules
3) ./result/bin/otbcli_BandMathX -help

Guide on installation related to NIX

Nix should be installed and flakes should be enabled. nix-direnv is optional but is also recommended.

NOTE: This repo is currently experimental, please open an issue in case you encounter any.

About

A Nix Flake configuration for building Orfeo Toolbox (OTB)

Resources

License

Stars

Watchers

Forks

Packages

No packages published