Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Monocular Depth Estimation: SC-DepthV3

demo_sc_depth/ScDepth.livemd

Monocular Depth Estimation: SC-DepthV3

File.cd!(__DIR__)
# for windows JP
# System.shell("chcp 65001")

Mix.install([
  {:onnx_interp, "~> 0.1.8"},
  {:cimg, "~> 0.1.18"},
  {:nx, "~> 0.4.2"},
  {:kino, "~> 0.8.0"}
])

0.Original work

SC-DepthV3: Robust Self-supervised Monocular Depth Estimation for Dynamic Scenes

GitHub: SC_Depth

This note usee the pretraind model converted from above project ;-)

Thanks a lot!!!


Implementation with OnnxInterp in Elixir

1.Defining the inference module: ScDepth

  • Model
    sc_depth-epoch=99-val_loss=0.1438.onnx

  • Pre-processing
    Resize the input image to the size {640,384}, gauss {{114.75,57.375},{114.75,57.375},{114.75,57.375}}} and transpose NCHW.

  • Post-processing
    normalize depth map and color-mapping.

defmodule ScDepth do
  @width 640
  @height 384

  alias OnnxInterp, as: NNInterp

  use NNInterp,
    model: "model/sc_depth-epoch=99-val_loss=0.1438.onnx",
    url:
      "https://github.com/shoz-f/onnx_interp/releases/download/models/sc_depth-epoch.99-val_loss.0.1438.onnx",
    inputs: [f32: {1, 3, @height, @width}],
    outputs: [f32: {1, 1, @height, @width}]

  def apply(img) do
    # preprocess
    input0 =
      CImg.builder(img)
      |> CImg.resize({@width, @height})
      |> CImg.to_binary([{:gauss, {{114.75, 57.375}, {114.75, 57.375}, {114.75, 57.375}}}, :nchw])

    # prediction
    output0 =
      session()
      |> NNInterp.set_input_tensor(0, input0)
      |> NNInterp.invoke()
      |> NNInterp.get_output_tensor(0)

    # postprocess
    {w, h, _, _} = CImg.shape(img)

    output0
    |> CImg.from_binary(@width, @height, 1, 1, range: min_max(output0), dtype: " CImg.resize({w, h})
  end

  defp min_max(bin) do
    t = Nx.from_binary(bin, :f32)

    {
      Nx.reduce_min(t) |> Nx.to_number(),
      Nx.reduce_max(t) |> Nx.to_number()
    }
  end
end

Launch ScDepth.

OnnxInterp.stop(ScDepth)
ScDepth.start_link([])

Display the properties of the ScDepth model.

OnnxInterp.info(ScDepth)

2.Defining execution module ScDepth

defmodule LiveScDepth do
  def run(path) do
    img = CImg.load(path)

    depth =
      ScDepth.apply(img)
      |> CImg.color_mapping(:jet)

    Kino.Layout.grid(
      Enum.map([img, depth], &CImg.display_kino(&1, :jpeg)),
      columns: 2
    )
  end
end

3.Let’s try it

LiveScDepth.run("sample.jpg")

Appendix

[1] export_onnx.py: python script to convert Pytorch checkpoint to ONNX.

import torch
import torch.onnx
from path import Path
import os

from config import get_opts, get_training_size

from SC_Depth import SC_Depth
from SC_DepthV2 import SC_DepthV2
from SC_DepthV3 import SC_DepthV3


@torch.no_grad()
def main():
    hparams = get_opts()

    if hparams.model_version == 'v1':
        system = SC_Depth(hparams)
    elif hparams.model_version == 'v2':
        system = SC_DepthV2(hparams)
    elif hparams.model_version == 'v3':
        system = SC_DepthV3(hparams)

    output_dir = Path(hparams.output_dir)
    output_dir.makedirs_p()

    system = system.load_from_checkpoint(hparams.ckpt_path, strict=False)

    model = system.depth_net
    model.eval()

    # training size
    training_size = get_training_size(hparams.dataset_name)
    dummy_input = torch.randn(1, 3, *training_size)

    # export the model
    torch.onnx.export(model,
        dummy_input,
        output_dir / Path(hparams.ckpt_path).stem + ".onnx",
        export_params=True,
        #opset_version=10,
        do_constant_folding=True,
        input_names=["input.0"],
        output_names=["output.0"],
        #dynamic_axes={}
        )


if __name__ == '__main__':
    main()