【RealSense D415】深さの分解能変更



C#で使うとき、深さの分解能変更方法が良く分からなくてうろうろしました・・・・。

この目的に対しては↓で解決しました。

```C#
depthSensor.Options[Option.DepthUnits].Value = 0.00001f;
```
これで最小分解能は0.01mmになりました。

#注意点
分解能を変えると最大値が変わります。
例えば

```C#
depthSensor.Options[Option.DepthUnits].Value = 0.00001f;
```
だと最大値が655.35mmになってしまいます。
計測値は16bitの整数で表現され最小分解能をどこに置くか、と言うことになる様です。

```C#
depthSensor.Options[Option.DepthUnits].Value = 0.0001f;
```
とすれば

* 最小分解能 0.1mm
* 最大値 6553.5mm

になります。
ハードウェア性能も10m、これを使う目的も0.1mmまで取れれば大抵使えそうなので、この辺りが良いところかなーと思います。


サンプルをいじったコード↓

```C#
class Program
{
static void Main(string[] args)
{
    var size = new Size(1280, 720);
    
    using (var ctx = new Context())
    {

        var devices = ctx.QueryDevices();

        Console.WriteLine("There are {0} connected RealSense devices.", devices.Count);
        if (devices.Count == 0) return;
        var dev = devices[0];

        Console.WriteLine("\nUsing device 0, an {0}", dev.Info[CameraInfo.Name]);
        Console.WriteLine("    Serial number: {0}", dev.Info[CameraInfo.SerialNumber]);
        Console.WriteLine("    Firmware version: {0}", dev.Info[CameraInfo.FirmwareVersion]);

        var depthSensor = dev.QuerySensors<Sensor>()[0];
        var candidate = depthSensor.StreamProfiles
                            .Where(p => p.Stream == Stream.Depth)
                            .OrderBy(p => p.Framerate)
                            .Select(p => p.As<VideoStreamProfile>());
        var sp = candidate
                            .First(p => p.Width == size.Width && p.Height == size.Height);
        depthSensor.Options[Option.DepthUnits].Value = 0.00001f;


        int one_meter = (int)(1f / depthSensor.DepthScale);
        ushort[] depth = new ushort[(int)(size.Width * size.Height)];
        char[] buffer = new char[(int)((size.Width / 10 + 1) * (size.Height / 20))];
        int[] coverage = new int[64];

        depthSensor.Open(sp);

        depthSensor.Start(f =>
        {
            
            using (var vf = f.As<VideoFrame>())
                vf.CopyTo(depth);

            int b = 0;
            for (int y = 0; y < size.Height; ++y)
            {
                for (int x = 0; x < size.Width; ++x)
                {
                    ushort d = depth[(int)(x + y * size.Width)];

                    if (d > 0 && d < one_meter)
                        ++coverage[x / (int)(size.Width / coverage.Length) ];
                }

                if (y % 20 == 19)
                {
                    for (int i = 0; i < coverage.Length; i++)
                    {
                        int c = coverage[i];
                        buffer[b++] = " .:nhBXWW"[c / 100];
                        coverage[i] = 0;
                    }
                    buffer[b++] = '\n';
                }
            }

            Console.SetCursorPosition(0, 0);
            Console.WriteLine();
            Console.Write(buffer);
            Console.WriteLine();

            using (var depthFrame = f.As<DepthFrame>())
            {
                if (depthFrame != null)
                {
                    Console.WriteLine("The camera is pointing at an object " +
                        depthFrame.GetDistance(depthFrame.Width / 2, depthFrame.Height / 2).ToString("F7") + " meters away\t");

                    Console.SetCursorPosition(0, 0);
                }
            }


        });

        AutoResetEvent stop = new AutoResetEvent(false);
        Console.CancelKeyPress += (s, e) =>
        {
            e.Cancel = true;
            stop.Set();
        };
        stop.WaitOne();

        depthSensor.Stop();
        depthSensor.Close();
    }
}
}

```


#課題
分解能を高めていくと近い部分の距離が測れないのが気になります。
実際にD415で上の設定だけ変えて計測すると400mm程度以下の数値が0でクリップされて計測できません。

ちょっと時間切れで詳しく調べられていないのですが、
[ここ](https://github.com/IntelRealSense/librealsense/issues/1171)によれば15cm～20cmが計測できるそうなのです。
ここで言及される
Disparity Shift (under Advanced Controls > Depth Table)
がC#のラッパでどう変更するのか分かりませんでした。