예제 #1
0
        /// <summary>
        /// Sets the image wrapper provided to a property.
        /// </summary>
        /// <param name="nativeMethod">Native set method.</param>
        /// <param name="cachedImage">Reference to the cached image wrapper used by this class.</param>
        /// <param name="value">Value to assign the image wrapper to.</param>
        /// <remarks>
        /// This function takes ownership of the wrapper and stores it in the class. If there was
        /// a previous wrapper owned by the class, this function will dispose it.
        /// </remarks>
        private void SetImageWrapperAndDisposePrevious(
            Action <NativeMethods.k4a_capture_t, NativeMethods.k4a_image_t> nativeMethod,
            ref Image cachedImage,
            Image value)
        {
            lock (this)
            {
                if (this.disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Capture));
                }

                // If the assignment is a new managed wrapper we need
                // to release the reference to the old wrapper.
                // If it is the same object though, we should not dispose it.
                if (cachedImage != null && !object.ReferenceEquals(
                        cachedImage, value))
                {
                    cachedImage.Dispose();
                }

                cachedImage = value;

                // Take an extra reference on the image to ensure it isn't disposed
                // prior while we have the handle.
                using (Image reference = cachedImage.Reference())
                {
                    nativeMethod(this.handle, cachedImage.DangerousGetHandle());
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Transforms an Image from the color camera perspective to the depth camera perspective.
        /// </summary>
        /// <param name="depth">Depth map of the space the color image is being transformed in to.</param>
        /// <param name="color">Color image to transform in to the depth space.</param>
        /// <param name="transformed">An Image to hold the output.</param>
        /// <remarks>
        /// The <paramref name="transformed"/> Image must be of the resolution of the depth camera, and
        /// of the pixel format of the color image.
        /// </remarks>
        public void ColorImageToDepthCamera(Image depth, Image color, Image transformed)
        {
            if (depth == null)
            {
                throw new ArgumentNullException(nameof(depth));
            }

            if (color == null)
            {
                throw new ArgumentNullException(nameof(color));
            }

            if (transformed == null)
            {
                throw new ArgumentNullException(nameof(transformed));
            }

            lock (this)
            {
                if (this.disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Transformation));
                }

                // Create a new reference to the Image objects so that they cannot be disposed while
                // we are performing the transformation
                using (Image depthReference = depth.Reference())
                    using (Image colorReference = color.Reference())
                        using (Image transformedReference = transformed.Reference())
                        {
                            // Ensure changes made to the managed memory are visible to the native layer
                            depthReference.FlushMemory();
                            colorReference.FlushMemory();

                            AzureKinectException.ThrowIfNotSuccess(() => NativeMethods.k4a_transformation_color_image_to_depth_camera(
                                                                       this.handle,
                                                                       depthReference.DangerousGetHandle(),
                                                                       colorReference.DangerousGetHandle(),
                                                                       transformedReference.DangerousGetHandle()));

                            // Copy the native memory back to managed memory if required
                            transformedReference.InvalidateMemory();
                        }
            }
        }
예제 #3
0
        /// <summary>
        /// Transform a 2D pixel coordinate from color camera into a 2D pixel coordinate of the depth camera.
        /// </summary>
        /// <param name="sourcePoint2D">The 2D pixel color camera coordinates.</param>
        /// <param name="depth">The depth image.</param>
        /// <returns>The 2D pixel in depth camera coordinates, or null if the source point is not valid in the depth camera coordinate system.</returns>
        public Vector2?TransformColor2DToDepth2D(Vector2 sourcePoint2D, Image depth)
        {
            if (depth == null)
            {
                throw new ArgumentNullException(nameof(depth));
            }

            using (LoggingTracer tracer = new LoggingTracer())
                using (Image depthReference = depth.Reference())
                {
                    AzureKinectException.ThrowIfNotSuccess(tracer, NativeMethods.k4a_calibration_color_2d_to_depth_2d(
                                                               ref this,
                                                               ref sourcePoint2D,
                                                               depthReference.DangerousGetHandle(),
                                                               out Vector2 target_point2d,
                                                               out bool valid));

                    return(valid ? (Vector2?)target_point2d : null);
                }
        }
        public static Bitmap CreateBitmap(this Microsoft.Azure.Kinect.Sensor.Image image)
        {
            if (image is null)
            {
                throw new ArgumentNullException(nameof(image));
            }

            System.Drawing.Imaging.PixelFormat pixelFormat;

            using (Microsoft.Azure.Kinect.Sensor.Image reference = image.Reference())
            {
                unsafe
                {
                    switch (reference.Format)
                    {
                    case ImageFormat.ColorBGRA32:
                        pixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
                        break;

                    case ImageFormat.Depth16:
                    case ImageFormat.IR16:
                        pixelFormat = System.Drawing.Imaging.PixelFormat.Format16bppGrayScale;
                        break;

                    default:
                        throw new AzureKinectException($"Pixel format {reference.Format} cannot be converted to a BitmapSource");
                    }

                    using (MemoryHandle pin = image.Memory.Pin())
                    {
                        return(new Bitmap(
                                   image.WidthPixels,
                                   image.HeightPixels,
                                   image.StrideBytes,
                                   pixelFormat,
                                   (IntPtr)pin.Pointer));
                    }
                }
            }
        }
예제 #5
0
        public void DepthImageToColorCamera(Image depth, Image transformed)
        {
            lock (this)
            {
                if (disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Transformation));
                }

                // Create a new reference to the Image objects so that they cannot be disposed while
                // we are performing the transformation
                using (Image depthReference = depth.Reference())
                    using (Image transformedReference = transformed.Reference())
                    {
                        AzureKinectException.ThrowIfNotSuccess(NativeMethods.k4a_transformation_depth_image_to_color_camera(
                                                                   handle,
                                                                   depthReference.DangerousGetHandle(),
                                                                   transformedReference.DangerousGetHandle()
                                                                   ));
                    }
            }
        }
예제 #6
0
        public void DepthImageToPointCloud(Image depth, Image pointCloud, Calibration.DeviceType camera = Calibration.DeviceType.Depth)
        {
            lock (this)
            {
                if (disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Transformation));
                }

                // Create a new reference to the Image objects so that they cannot be disposed while
                // we are performing the transformation
                using (Image depthReference = depth.Reference())
                    using (Image pointCloudReference = pointCloud.Reference())
                    {
                        AzureKinectException.ThrowIfNotSuccess(NativeMethods.k4a_transformation_depth_image_to_point_cloud(
                                                                   handle,
                                                                   depthReference.DangerousGetHandle(),
                                                                   camera,
                                                                   pointCloudReference.DangerousGetHandle()));
                    }
            }
        }
예제 #7
0
        /// <summary>
        /// Creates a point cloud from a depth image.
        /// </summary>
        /// <param name="depth">The depth map to generate the point cloud from.</param>
        /// <param name="pointCloud">The image to store the output point cloud.</param>
        /// <param name="camera">The perspective the depth map is from.</param>
        /// <remarks>
        /// If the depth map is from the original depth perspective, <paramref name="camera"/> should be Depth. If it has
        /// been transformed to the color camera perspective, <paramref name="camera"/> should be Color.
        ///
        /// The <paramref name="pointCloud"/> image must be of format Custom. Each pixel will be an XYZ set of 16 bit values,
        /// therefore its stride must be 2(bytes) * 3(x,y,z) * width of the <paramref name="depth"/> image in pixels.
        /// </remarks>
        public void DepthImageToPointCloud(Image depth, Image pointCloud, CalibrationDeviceType camera = CalibrationDeviceType.Depth)
        {
            if (depth == null)
            {
                throw new ArgumentNullException(nameof(depth));
            }

            if (pointCloud == null)
            {
                throw new ArgumentNullException(nameof(pointCloud));
            }

            lock (this)
            {
                if (this.disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Transformation));
                }

                // Create a new reference to the Image objects so that they cannot be disposed while
                // we are performing the transformation
                using (Image depthReference = depth.Reference())
                    using (Image pointCloudReference = pointCloud.Reference())
                    {
                        // Ensure changes made to the managed memory are visible to the native layer
                        depthReference.FlushMemory();

                        AzureKinectException.ThrowIfNotSuccess(() => NativeMethods.k4a_transformation_depth_image_to_point_cloud(
                                                                   this.handle,
                                                                   depthReference.DangerousGetHandle(),
                                                                   camera,
                                                                   pointCloudReference.DangerousGetHandle()));

                        // Copy the native memory back to managed memory if required
                        pointCloudReference.InvalidateMemory();
                    }
            }
        }
예제 #8
0
        /// <summary>
        /// Transforms a depth Image and a custom Image from the depth camera perspective to the color camera perspective.
        /// </summary>
        /// <param name="depth">Depth image to transform.</param>
        /// <param name="custom">Custom image to transform.</param>
        /// <param name="transformedDepth">An transformed depth image to hold the output.</param>
        /// <param name="transformedCustom">An transformed custom image to hold the output.</param>
        /// <param name="interpolationType">Parameter that controls how pixels in custom image should be interpolated when transformed to color camera space.</param>
        /// <param name="invalidCustomValue">Defines the custom image pixel value that should be written to transformedCustom in case the corresponding depth pixel can not be transformed into the color camera space.</param>
        /// <remarks>
        /// The <paramref name="transformedDepth"/> Image must be of the resolution of the color camera, and
        /// of the pixel format of the depth image.
        /// The <paramref name="transformedCustom"/> Image must be of the resolution of the color camera, and
        /// of the pixel format of the custom image.
        /// </remarks>
        public void DepthImageToColorCameraCustom(Image depth, Image custom, Image transformedDepth, Image transformedCustom, TransformationInterpolationType interpolationType, uint invalidCustomValue)
        {
            if (depth == null)
            {
                throw new ArgumentNullException(nameof(depth));
            }

            if (custom == null)
            {
                throw new ArgumentNullException(nameof(custom));
            }

            if (transformedDepth == null)
            {
                throw new ArgumentNullException(nameof(transformedDepth));
            }

            if (transformedCustom == null)
            {
                throw new ArgumentNullException(nameof(transformedCustom));
            }

            if (custom.Format != ImageFormat.Custom8 && custom.Format != ImageFormat.Custom16)
            {
                throw new NotSupportedException("Failed to support this format of custom image!");
            }

            if (transformedCustom.Format != ImageFormat.Custom8 && transformedCustom.Format != ImageFormat.Custom16)
            {
                throw new NotSupportedException("Failed to support this format of transformed custom image!");
            }

            if (custom.Format != transformedCustom.Format)
            {
                throw new NotSupportedException("Failed to support this different format of custom image and transformed custom image!!");
            }

            lock (this)
            {
                // Create a new reference to the Image objects so that they cannot be disposed while
                // we are performing the transformation
                using (Image depthReference = depth.Reference())
                    using (Image customReference = custom.Reference())
                        using (Image transformedDepthReference = transformedDepth.Reference())
                            using (Image transformedCustomReference = transformedCustom.Reference())
                            {
                                // Ensure changes made to the managed memory are visible to the native layer
                                depthReference.FlushMemory();
                                customReference.FlushMemory();

                                AzureKinectException.ThrowIfNotSuccess(() => NativeMethods.k4a_transformation_depth_image_to_color_camera_custom(
                                                                           this.handle,
                                                                           depthReference.DangerousGetHandle(),
                                                                           customReference.DangerousGetHandle(),
                                                                           transformedDepthReference.DangerousGetHandle(),
                                                                           transformedCustom.DangerousGetHandle(),
                                                                           interpolationType,
                                                                           invalidCustomValue));

                                // Copy the native memory back to managed memory if required
                                transformedDepthReference.InvalidateMemory();
                                transformedCustom.InvalidateMemory();
                            }
            }
        }
예제 #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AzureKinectMemoryManager"/> class.
 /// </summary>
 /// <param name="image">Image with native memory.</param>
 /// <remarks>
 /// Constructs a new MemoryManager representing the native memory backing an Image.
 /// </remarks>
 internal AzureKinectMemoryManager(Image image)
 {
     this.image = image.Reference();
 }
예제 #10
0
        /// <summary>
        /// Retrieves a native image handle from the native API.
        /// </summary>
        /// <param name="nativeMethod">Native method to retrieve the image.</param>
        /// <param name="cachedImage">A cached instance of the Image that we return to callers. (Callers may dispose this image, although they shouldn't).</param>
        /// <remarks>
        /// If this is the first time calling the property, we construct a new wrapper.
        /// If the handle is for an Image we have already constructed a wrapper for, we return the existing wrapper.
        /// If the handle is for a different Image, we construct a new wrapper and dispose the old one.
        /// If existing wrapper has been disposed, we throw an exception.
        /// </remarks>
        private void UpdateImageWrapperAndDisposePrevious(
            Func <NativeMethods.k4a_capture_t, NativeMethods.k4a_image_t> nativeMethod,
            ref Image cachedImage)
        {
            // Lock must be held to ensure the Image in cache is not replaced while we are inspecting it
            // It is still possible for that Image to be accessed or Disposed while this lock is held
            lock (this)
            {
                if (this.disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Capture));
                }

                // Get the image object from the native SDK
                // We now own a reference on this image and must eventually release it.
                NativeMethods.k4a_image_t nativeImageHandle = nativeMethod(this.handle);

                // This try block ensures that we close image (and release our reference) if we fail
                // to create a new Image.
                try
                {
                    // If this Capture previously had an image
                    if (cachedImage != null)
                    {
                        // Get the native pointer
                        IntPtr imageHandleValue = nativeImageHandle.DangerousGetHandle();

                        // Get the handle value from the cached image. If it has been disposed, this
                        // will throw an exception, which will be passed to the caller.

                        // Take an extra reference on the cachedImage to ensure it doesn't get disposed
                        // after getting the IntPtr from the handle.
                        using (Image reference = cachedImage.Reference())
                        {
                            if (reference.DangerousGetHandle().DangerousGetHandle() != imageHandleValue)
                            {
                                // The image has changed, invalidate the current image and construct new wrappers
                                cachedImage.Dispose();
                                cachedImage = null;
                            }
                        }
                    }

                    if (cachedImage == null && !nativeImageHandle.IsInvalid)
                    {
                        // Construct a new wrapper and return it
                        // The native function may have returned
#pragma warning disable CA2000 // Dispose objects before losing scope
                        cachedImage = new Image(nativeImageHandle);
#pragma warning restore CA2000 // Dispose objects before losing scope

                        // Since we have wrapped image, it is now owned by Image and we should no longer close it
                        nativeImageHandle = null;
                    }
                }
                finally
                {
                    // Ensure the native handle is closed if we have a failure creating the Image object
                    if (nativeImageHandle != null)
                    {
                        nativeImageHandle.Close();
                    }
                }
            }
        }