Beispiel #1
0
        private readonly NativeHandles.HandleWrapper <NativeHandles.PlaybackHandle> handle;      // This class is an wrapper around this handle

        /// <summary>Opens an existing recording file for reading.</summary>
        /// <param name="filePath">File system path of the existing recording. Not <see langword="null"/>. Not empty.</param>
        /// <exception cref="ArgumentNullException"><paramref name="filePath"/> is null or empty.</exception>
        /// <exception cref="ArgumentException"><paramref name="filePath"/> contains some invalid character. Also, right now non-Latin letters are not supported in <paramref name="filePath"/> under Windows.</exception>
        /// <exception cref="FileNotFoundException">Files specified in <paramref name="filePath"/> does not exist.</exception>
        /// <exception cref="PlaybackException">Cannot open file specified in <paramref name="filePath"/> for playback. See logs for details.</exception>
        public Playback(string filePath)
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }
            if (filePath.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
            {
                throw new ArgumentException($"Path \"{filePath}\" contains invalid characters.", nameof(filePath));
            }
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"Cannot find file \"{filePath}\".", filePath);
            }

            var pathAsBytes = Helpers.FilePathNameToBytes(filePath);

            var res = NativeApi.PlaybackOpen(pathAsBytes, out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new PlaybackException($"Cannot open file \"{filePath}\" for playback.", filePath);
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;

            FilePath = filePath;
        }
Beispiel #2
0
        /// <summary>Creates a body tracker.</summary>
        /// <param name="calibration">The sensor calibration that will be used for capture processing.</param>
        /// <param name="config">The configuration we want to run the tracker in. This can be initialized with <see cref="TrackerConfiguration.Default"/>.</param>
        /// <remarks><para>
        /// Under the hood Body Tracking runtime will be initialized during the first call of this constructor.
        /// It is rather time consuming operation: initialization of ONNX runtime, loading and parsing of neural network model, etc.
        /// For this reason, it is recommended to initialize Body Tracking runtime in advance: <see cref="Sdk.TryInitializeBodyTrackingRuntime(out string)"/>.
        /// </para><para>
        /// Also, Body Tracking runtime must be available in one of the following locations:
        /// directory with executable file,
        /// directory with <c>K4AdotNet</c> assembly,
        /// installation directory of Body Tracking SDK under <c>Program Files</c>.
        /// </para></remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Invalid value of <paramref name="calibration"/>: <see cref="Calibration.DepthMode"/> cannot be <see cref="DepthMode.Off"/> and <see cref="DepthMode.PassiveIR"/>.
        /// Because depth data is required for body tracking.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// Only one tracker is allowed to exist at the same time in each process. If you call this constructor without destroying the
        /// previous tracker you created, the constructor call will fail with this exception.
        /// </exception>
        /// <exception cref="BodyTrackingException">
        /// Unable to find/initialize Body Tracking runtime.
        /// </exception>
        /// <seealso cref="Sdk.IsBodyTrackingRuntimeAvailable(out string)"/>
        /// <seealso cref="Sdk.TryInitializeBodyTrackingRuntime(out string)"/>
        public Tracker(ref Calibration calibration, TrackerConfiguration config = default(TrackerConfiguration))
        {
            if (!calibration.DepthMode.HasDepth())
            {
                throw new ArgumentOutOfRangeException(nameof(calibration) + "." + nameof(calibration.DepthMode));
            }

            DepthMode = calibration.DepthMode;

            var incrementedInstanceCounter = Interlocked.Increment(ref instancesCounter);

            try
            {
                if (incrementedInstanceCounter != 1)
                {
                    throw new NotSupportedException("Oops! Current version of Body Tracking runtime does not support creation of multiple body trackers. Sorry!");
                }

                if (!Sdk.TryCreateTrackerHandle(ref calibration, config, out var handle, out var message))
                {
                    throw new BodyTrackingException(message);
                }

                this.handle           = handle;
                this.handle.Disposed += Handle_Disposed;
            }
            catch
            {
                Interlocked.Decrement(ref instancesCounter);
                throw;
            }
        }
Beispiel #3
0
        // Don't use this method to create image with unknown/unspecified stride (like MJPEG).
        // For such formats, size of image in bytes must be specified to create image.
        public Image(ImageFormat format, int widthPixels, int heightPixels, int strideBytes)
        {
            if (widthPixels <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(widthPixels));
            }
            if (heightPixels <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(heightPixels));
            }
            if (strideBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(strideBytes));
            }
            if (strideBytes == 0)
            {
                throw new InvalidOperationException("Zero stride is used for formats without complex structure like MJPEG. In this case size of image in bytes must be specified to create image.");
            }
            if (format.HasKnownBytesPerPixel() && strideBytes < widthPixels * format.BytesPerPixel())
            {
                throw new ArgumentOutOfRangeException(nameof(strideBytes));
            }

            var res = NativeApi.ImageCreate(format, widthPixels, heightPixels, strideBytes, out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new ArgumentException($"Cannot create image with format {format}, size {widthPixels}x{heightPixels} pixels and stride {strideBytes} bytes.");
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #4
0
 private Device(NativeHandles.DeviceHandle handle, string serialNumber, HardwareVersion version)
 {
     this.handle           = handle;
     this.handle.Disposed += Handle_Disposed;
     SerialNumber          = serialNumber;
     Version = version;
 }
Beispiel #5
0
        public Recorder(string filePath, Sensor.Device device, Sensor.DeviceConfiguration config)
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }
            if (filePath.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
            {
                throw new ArgumentException($"Path \"{filePath}\" contains invalid characters.", nameof(filePath));
            }

            var pathAsBytes = Helpers.FilePathNameToBytes(filePath);

            var res = NativeApi.RecordCreate(pathAsBytes, Sensor.Device.ToHandle(device), config, out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new RecordingException($"Cannot initialize recording to file \"{filePath}\".");
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;

            FilePath = filePath;
        }
Beispiel #6
0
        private readonly NativeHandles.HandleWrapper <NativeHandles.CaptureHandle> handle;  // this class is an wrapper around this handle

        /// <summary>Creates an empty capture object.</summary>
        /// <exception cref="InvalidOperationException">
        /// Sensor SDK fails to create empty capture object for some reason. For details see logs.
        /// </exception>
        public Capture()
        {
            var res = NativeApi.CaptureCreate(out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new InvalidOperationException("Failed to create blank capture instance");
            }
            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #7
0
        public Transformation(ref Calibration calibration)
        {
            var handle = NativeApi.TransformationCreate(ref calibration);

            if (handle == null || handle.IsInvalid)
            {
                throw new ArgumentException("Cannot create transformation object from specified calibration data (or depthengine_1_0.dll library cannot be found).", nameof(calibration));
            }
            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
            DepthMode             = calibration.DepthMode;
            ColorResolution       = calibration.ColorResolution;
        }
Beispiel #8
0
        public Tracker(ref Sensor.Calibration calibration)
        {
            if (Interlocked.Increment(ref instancesCounter) != 1)
            {
                Interlocked.Decrement(ref instancesCounter);
                throw new NotSupportedException("Oops! Current version of Body Tracking SDK does not support creation of multiple body tracker. Sorry!");
            }

            if (NativeApi.TrackerCreate(ref calibration, out var handle) != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
                throw new BodyTrackingException("Cannot initialize body tracking infrastructure");

            this.handle = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #9
0
        /// <summary>
        /// Creates transformation object for a give calibration data.
        /// </summary>
        /// <param name="calibration">Camera calibration data.</param>
        /// <remarks><para>
        /// Each transformation instance requires some pre-computed resources to be allocated,
        /// which are retained until the call of <see cref="Dispose"/> method.
        /// </para><para>
        /// <see cref="Sdk.DEPTHENGINE_DLL_NAME"/> library is required for this functionality.
        /// </para></remarks>
        /// <exception cref="InvalidOperationException">Something wrong with calibration data or <see cref="Sdk.DEPTHENGINE_DLL_NAME"/> library cannot be loaded.</exception>
        /// <seealso cref="Dispose"/>
        public Transformation(ref Calibration calibration)
        {
            var handle = NativeApi.TransformationCreate(ref calibration);

            if (handle == null || handle.IsInvalid)
            {
                throw new InvalidOperationException(
                          $"Cannot create transformation object from specified calibration data or {Sdk.DEPTHENGINE_DLL_NAME} library cannot be found).");
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;

            DepthMode       = calibration.DepthMode;
            ColorResolution = calibration.ColorResolution;
        }
Beispiel #10
0
        /// <summary>Creates a body tracker.</summary>
        /// <param name="calibration">The sensor calibration that will be used for capture processing.</param>
        /// <param name="config">The configuration we want to run the tracker in. This can be initialized with <see cref="TrackerConfiguration.Default"/>.</param>
        /// <remarks><para>
        /// Under the hood Body Tracking runtime will be initialized during the first call of this constructor.
        /// It is rather time consuming operation: initialization of ONNX runtime, loading and parsing of neural network model, etc.
        /// For this reason, it is recommended to initialize Body Tracking runtime in advance: <see cref="Sdk.TryInitializeBodyTrackingRuntime(out string)"/>.
        /// </para><para>
        /// Also, Body Tracking runtime must be available in one of the following locations:
        /// directory with executable file,
        /// directory with <c>K4AdotNet</c> assembly,
        /// installation directory of Body Tracking SDK under <c>Program Files</c>.
        /// </para></remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Invalid value of <paramref name="calibration"/>: <see cref="Calibration.DepthMode"/> cannot be <see cref="DepthMode.Off"/> and <see cref="DepthMode.PassiveIR"/>.
        /// Because depth data is required for body tracking.
        /// </exception>
        /// <exception cref="BodyTrackingException">
        /// Unable to find/initialize Body Tracking runtime.
        /// </exception>
        /// <seealso cref="Sdk.IsBodyTrackingRuntimeAvailable(out string)"/>
        /// <seealso cref="Sdk.TryInitializeBodyTrackingRuntime(out string)"/>
        public Tracker(ref Calibration calibration, TrackerConfiguration config = default)
        {
            if (!calibration.DepthMode.HasDepth())
            {
                throw new ArgumentOutOfRangeException(nameof(calibration) + "." + nameof(calibration.DepthMode));
            }

            DepthMode = calibration.DepthMode;

            if (!Sdk.TryCreateTrackerHandle(ref calibration, config, out var handle, out var message))
            {
                throw new BodyTrackingException(message);
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #11
0
        /// <summary>Creates new image with specified format, size in pixels and stride in bytes.</summary>
        /// <param name="format">Format of image. Must be format with known stride: <see cref="ImageFormats.StrideBytes(ImageFormat, int)"/>.</param>
        /// <param name="widthPixels">Width of image in pixels. Must be positive.</param>
        /// <param name="heightPixels">Height of image in pixels. Must be positive.</param>
        /// <param name="strideBytes">Image stride in bytes (the number of bytes per horizontal line of the image). Must be non-negative. Zero value can be used for <see cref="ImageFormat.ColorMjpg"/> and <see cref="ImageFormat.Custom"/>.</param>
        /// <param name="sizeBytes">Size of image buffer in size. Non negative. Cannot be less than size calculated from image parameters.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="widthPixels"/> or <paramref name="heightPixels"/> is equal to or less than zero
        /// or <paramref name="strideBytes"/> is less than zero or <paramref name="strideBytes"/> is too small for specified <paramref name="format"/>
        /// or <paramref name="sizeBytes"/> is less than zero or <paramref name="sizeBytes"/> is less than size calculated from <paramref name="heightPixels"/> and <paramref name="strideBytes"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// <paramref name="strideBytes"/> is equal to zero. In this case size of image in bytes must be specified to create image.
        /// </exception>
        public Image(ImageFormat format, int widthPixels, int heightPixels, int strideBytes, int sizeBytes)
        {
            if (widthPixels <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(widthPixels));
            }
            if (heightPixels <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(heightPixels));
            }
            if (strideBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(strideBytes));
            }
            if (format.HasKnownBytesPerPixel() && strideBytes < widthPixels * format.BytesPerPixel())
            {
                throw new ArgumentOutOfRangeException(nameof(strideBytes));
            }
            if (sizeBytes <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(sizeBytes));
            }
            if (strideBytes > 0 && sizeBytes < format.ImageSizeBytes(strideBytes, heightPixels))
            {
                throw new ArgumentOutOfRangeException(nameof(sizeBytes));
            }

            var buffer = Marshal.AllocHGlobal(sizeBytes);

            if (buffer == IntPtr.Zero)
            {
                throw new OutOfMemoryException($"Cannot allocate buffer of {sizeBytes} bytes.");
            }

            var res = NativeApi.ImageCreateFromBuffer(format, widthPixels, heightPixels, strideBytes,
                                                      buffer, Helpers.Int32ToUIntPtr(sizeBytes), unmanagedBufferReleaseCallback, IntPtr.Zero,
                                                      out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new ArgumentException($"Cannot create image with format {format}, size {widthPixels}x{heightPixels} pixels, stride {strideBytes} bytes from buffer of size {sizeBytes} bytes.");
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #12
0
        /// <summary>Creates new image with specified format, size in pixels and stride in bytes.</summary>
        /// <param name="format">Format of image. Must be format with known stride: <see cref="ImageFormats.StrideBytes(ImageFormat, int)"/>.</param>
        /// <param name="widthPixels">Width of image in pixels. Must be positive.</param>
        /// <param name="heightPixels">Height of image in pixels. Must be positive.</param>
        /// <param name="strideBytes">Image stride in bytes (the number of bytes per horizontal line of the image). Must be positive.</param>
        /// <remarks>
        /// Don't use this method to create image with unknown/unspecified stride (like MJPEG).
        /// For such formats, size of image in bytes must be specified to create image: <see cref="Image.Image(ImageFormat, int, int, int, int)"/>.
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="widthPixels"/> or <paramref name="heightPixels"/> is equal to or less than zero
        /// or <paramref name="strideBytes"/> is less than zero or <paramref name="strideBytes"/> is too small for specified <paramref name="format"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// <paramref name="strideBytes"/> is equal to zero. In this case size of image in bytes must be specified to create image.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// If <paramref name="format"/> equals to <see cref="ImageFormat.ColorNV12"/>.
        /// For details see https://github.com/microsoft/Azure-Kinect-Sensor-SDK/issues/587.
        /// </exception>
        public Image(ImageFormat format, int widthPixels, int heightPixels, int strideBytes)
        {
            if (widthPixels <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(widthPixels));
            }
            if (heightPixels <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(heightPixels));
            }
            if (strideBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(strideBytes));
            }
            if (strideBytes == 0)
            {
                throw new InvalidOperationException("Zero stride is used for formats with complex structure like MJPEG. In this case size of image in bytes must be specified to create image.");
            }
            if (format.HasKnownBytesPerPixel() && strideBytes < widthPixels * format.BytesPerPixel())
            {
                throw new ArgumentOutOfRangeException(nameof(strideBytes));
            }

            if (format == ImageFormat.ColorNV12)
            {
                // Because of bug in Sensor DK
                // See https://github.com/microsoft/Azure-Kinect-Sensor-SDK/issues/587
                throw new NotSupportedException($"Please, specify size of image data in bytes for {format} format. This is because of issue #587 in Sensor DK.");
            }

            var res = NativeApi.ImageCreate(format, widthPixels, heightPixels, strideBytes, out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new ArgumentException($"Cannot create image with format {format}, size {widthPixels}x{heightPixels} pixels and stride {strideBytes} bytes.");
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #13
0
        private readonly NativeHandles.HandleWrapper <NativeHandles.RecordHandle> handle;        // This class is an wrapper around this handle

        /// <summary>
        /// Opens a new recording file for writing.
        /// </summary>
        /// <param name="filePath">File system path for the new recording. Not <see langword="null"/>, not empty.</param>
        /// <param name="device">The Azure Kinect device that is being recorded. The device is used to store device calibration and serial
        /// number information. May be <see langword="null"/> if recording user-generated data.</param>
        /// <param name="config">The configuration the Azure Kinect device was started with. Must be valid: see <see cref="Sensor.DeviceConfiguration.IsValid"/>.</param>
        /// <remarks><para>
        /// The file will be created if it doesn't exist, or overwritten if an existing file is specified.
        /// </para><para>
        /// Streaming does not need to be started on the device at the time this function is called, but when it is started
        /// it should be started with the same configuration provided in <paramref name="config"/>.
        /// </para><para>
        /// Subsequent calls to <see cref="WriteCapture"/> will need to have images in the resolution and format defined
        /// in <paramref name="config"/>.
        /// </para></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="filePath"/> is null or empty.</exception>
        /// <exception cref="ArgumentException"><paramref name="config"/> is invalid or <paramref name="filePath"/> contains some invalid character. Also, right now non-Latin letters are not supported in <paramref name="filePath"/> under Windows.</exception>
        /// <exception cref="NotSupportedException">Color format is not supported for recorded. It is recommended to use <see cref="Sensor.ImageFormat.ColorMjpg"/> for recording.</exception>
        public Recorder(string filePath, Sensor.Device device, Sensor.DeviceConfiguration config)
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }
            if (filePath.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
            {
                throw new ArgumentException($"Path \"{filePath}\" contains invalid characters.", nameof(filePath));
            }
            if (!config.IsValid(out var message))
            {
                throw new ArgumentException(message, nameof(config));
            }
            if (config.ColorFormat == Sensor.ImageFormat.ColorBgra32)
            {
                throw new NotSupportedException($"Color format {config.ColorFormat} is not supported for recording. Recommended format: {Sensor.ImageFormat.ColorMjpg}.");
            }

            var pathAsBytes = Helpers.FilePathNameToBytes(filePath);

            var res = NativeApi.RecordCreate(pathAsBytes, Sensor.Device.ToHandle(device), config, out var handle);

            if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid)
            {
                throw new RecordingException($"Cannot initialize recording to file \"{filePath}\".", filePath);
            }

            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;

            FilePath            = filePath;
            DeviceConfiguration = config;

            CustomTracks = new RecorderCustomTrackCollection(this);
        }
Beispiel #14
0
        private readonly NativeHandles.HandleWrapper <NativeHandles.BodyFrameHandle> handle;    // this class is an wrapper around this handle

        private BodyFrame(NativeHandles.BodyFrameHandle handle)
        {
            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #15
0
        private readonly NativeHandles.HandleWrapper <NativeHandles.ImageHandle> handle;     // This class is an wrapper around this handle

        private Image(NativeHandles.ImageHandle handle)
        {
            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #16
0
        private readonly NativeHandles.HandleWrapper <NativeHandles.PlaybackDataBlockHandle> handle;     // this class is an wrapper around this handle

        private PlaybackDataBlock(NativeHandles.PlaybackDataBlockHandle handle)
        {
            this.handle           = handle;
            this.handle.Disposed += Handle_Disposed;
        }
Beispiel #17
0
 private Capture(NativeHandles.CaptureHandle handle)
 {
     this.handle           = handle;
     this.handle.Disposed += Handle_Disposed;
 }