示例#1
0
        /// <summary>
        /// Returns a Tensor constructed from the data in the Bitmap. The Tensor's dimensions are
        /// ordered CHW (channel x height x width). The color channel dimension is in the same order
        /// as the original Bitmap data. For 24bit bitmaps, this will be BGR. For 32bit bitmaps this
        /// will be BGRA.
        /// </summary>
        /// <param name="bitmap">The bitmap.</param>
        /// <param name="allocator">The allocator.</param>
        /// <returns>Tensor.</returns>
        /// <exception cref="InvalidOperationException">Bitmap must be 24bit or 32bit</exception>
        public static NDArray ToTensor(this Bitmap bitmap, IAllocator allocator)
        {
            var cpuAllocator = new Cpu.CpuAllocator();

            int bytesPerPixel = 0;

            if (bitmap.PixelFormat == PixelFormat.Format24bppRgb)
            {
                bytesPerPixel = 3;
            }
            else if (bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
                     bitmap.PixelFormat == PixelFormat.Format32bppPArgb ||
                     bitmap.PixelFormat == PixelFormat.Format32bppRgb)
            {
                bytesPerPixel = 4;
            }
            else
            {
                throw new InvalidOperationException("Bitmap must be 24bit or 32bit");
            }

            var lockData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadOnly,
                bitmap.PixelFormat);

            try
            {
                var sizes   = new long[] { bitmap.Height, bitmap.Width, bytesPerPixel };
                var strides = new long[] { lockData.Stride, bytesPerPixel, 1 };
                using (var cpuByteTensor = new NDArray(cpuAllocator, DType.UInt8, sizes, strides))
                {
                    cpuByteTensor.Storage.CopyToStorage(cpuByteTensor.StorageOffset, lockData.Scan0, cpuByteTensor.Storage.ByteLength);
                    using (var permutedTensor = cpuByteTensor.Transpose(2, 0, 1))
                    {
                        using (var cpuFloatTensor = new NDArray(cpuAllocator, DType.Float32, permutedTensor.Shape))
                        {
                            Ops.Copy(cpuFloatTensor, permutedTensor);

                            // TODO this could be made more efficient by skipping a the following copy if allocator is a CpuAllocator,
                            // but make sure that in that case the result tensor is not disposed before returning.

                            var result = new NDArray(allocator, DType.Float32, permutedTensor.Shape);
                            Ops.Copy(result, cpuFloatTensor);
                            Ops.Div(result, result, 255);
                            return(result);
                        }
                    }
                }
            }
            finally
            {
                bitmap.UnlockBits(lockData);
            }
        }
示例#2
0
 /// <summary>
 /// Fills the one hot.
 /// </summary>
 /// <param name="result">The result.</param>
 /// <param name="labelCount">The label count.</param>
 /// <param name="labels">The labels.</param>
 public static void FillOneHot(NDArray src, int labelCount, int[] labels)
 {
     if (src.Storage is Cpu.CpuStorage)
     {
         DoFillOneHot(src, labelCount, labels);
     }
     else
     {
         //If the result is not on the CPU, it is much faster to build the tensor on the CPU and then copy
         //An alternative to this would be building a specific GPU kernel for this operation
         var cpuAlloc = new Cpu.CpuAllocator();
         using (var cpuResult = new NDArray(cpuAlloc, src.ElementType, src.Shape))
         {
             DoFillOneHot(cpuResult, labelCount, labels);
             Ops.Copy(src, cpuResult);
         }
     }
 }
示例#3
0
        /// <summary>
        /// Converts a Tensor to a Bitmap. Elements of the tensor are assumed to be normalized in the range [0, 1]
        /// The tensor must have one of the following structures:
        /// * 2D tensor - output is a 24bit BGR bitmap in greyscale
        /// * 3D tensor where first dimension has length 1 - output is 24bit BGR bitmap in greyscale
        /// * 3D tensor where first dimension has length 3 - output is 24bit BGR bitmap
        /// * 3D tensor where first dimension has length 4 - output is 32bit BGRA bitmap
        /// 2D tensors must be in HW (height x width) order;
        /// 3D tensors must be in CHW (channel x height x width) order.
        /// </summary>
        /// <param name="tensor">The tensor.</param>
        /// <returns>Bitmap.</returns>
        /// <exception cref="InvalidOperationException">
        /// tensor must have 2 or 3 dimensions
        /// or
        /// 3D tensor's first dimension (color channels) must be of length 1, 3 or 4
        /// </exception>
        public static Bitmap ToBitmap(this NDArray tensor)
        {
            if (tensor.DimensionCount != 2 && tensor.DimensionCount != 3)
            {
                throw new InvalidOperationException("tensor must have 2 or 3 dimensions");
            }

            if (tensor.DimensionCount == 3 &&
                (tensor.Shape[0] != 1 && tensor.Shape[0] != 3 && tensor.Shape[0] != 4))
            {
                throw new InvalidOperationException("3D tensor's first dimension (color channels) must be of length 1, 3 or 4");
            }

            NDArray src;

            if (tensor.DimensionCount == 2)
            {
                src = tensor.RepeatTensor(3, 1, 1);
            }
            else if (tensor.DimensionCount == 3 && tensor.Shape[0] == 1)
            {
                src = tensor.RepeatTensor(3, 1, 1);
            }
            else
            {
                src = tensor.CopyRef();
            }

            var cpuAllocator  = new Cpu.CpuAllocator();
            var bytesPerPixel = src.Shape[0];

            try
            {
                using (var cpuFloatTensor = new NDArray(cpuAllocator, DType.Float32, src.Shape))
                    using (var permutedFloatTensor = cpuFloatTensor.Transpose(1, 2, 0))
                    {
                        Ops.Copy(cpuFloatTensor, src);
                        Ops.Mul(cpuFloatTensor, cpuFloatTensor, 255);

                        var resultFormat = bytesPerPixel == 3 ? PixelFormat.Format24bppRgb : PixelFormat.Format32bppArgb;
                        var result       = new Bitmap((int)src.Shape[2], (int)src.Shape[1], resultFormat);



                        var lockData = result.LockBits(
                            new Rectangle(0, 0, result.Width, result.Height),
                            ImageLockMode.WriteOnly,
                            result.PixelFormat);

                        var sizes        = new long[] { result.Height, result.Width, bytesPerPixel };
                        var strides      = new long[] { lockData.Stride, bytesPerPixel, 1 };
                        var resultTensor = new NDArray(cpuAllocator, DType.UInt8, sizes, strides);

                        // Re-order tensor and convert to bytes
                        Ops.Copy(resultTensor, permutedFloatTensor);

                        var byteLength = lockData.Stride * lockData.Height;
                        resultTensor.Storage.CopyFromStorage(lockData.Scan0, resultTensor.StorageOffset, byteLength);

                        result.UnlockBits(lockData);
                        return(result);
                    }
            }
            finally
            {
                src.Dispose();
            }
        }