Example #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"></param>
        /// <param name="allocator"></param>
        /// <returns></returns>
        public static Tensor ToTensor(this Bitmap bitmap, IAllocator allocator)
        {
            Cpu.CpuAllocator 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");
            }

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

            try
            {
                long[] sizes   = new long[] { bitmap.Height, bitmap.Width, bytesPerPixel };
                long[] strides = new long[] { lockData.Stride, bytesPerPixel, 1 };
                using (Tensor cpuByteTensor = new Tensor(cpuAllocator, DType.UInt8, sizes, strides))
                {
                    cpuByteTensor.Storage.CopyToStorage(cpuByteTensor.StorageOffset, lockData.Scan0, cpuByteTensor.Storage.ByteLength);
                    using (Tensor permutedTensor = cpuByteTensor.Permute(2, 0, 1))
                    {
                        using (Tensor cpuFloatTensor = new Tensor(cpuAllocator, DType.Float32, permutedTensor.Sizes))
                        {
                            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.

                            Tensor result = new Tensor(allocator, DType.Float32, permutedTensor.Sizes);
                            Ops.Copy(result, cpuFloatTensor);
                            Ops.Div(result, result, 255);
                            return(result);
                        }
                    }
                }
            }
            finally
            {
                bitmap.UnlockBits(lockData);
            }
        }
Example #2
0
 public static void FillOneHot(Tensor result, int labelCount, int[] labels)
 {
     if (result.Storage is Cpu.CpuStorage)
     {
         DoFillOneHot(result, 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 Tensor(cpuAlloc, result.ElementType, result.Sizes))
         {
             DoFillOneHot(cpuResult, labelCount, labels);
             Ops.Copy(result, cpuResult);
         }
     }
 }
Example #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"></param>
        /// <returns></returns>
        public static Bitmap ToBitmap(this Tensor tensor)
        {
            if (tensor.DimensionCount != 2 && tensor.DimensionCount != 3)
            {
                throw new InvalidOperationException("tensor must have 2 or 3 dimensions");
            }

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

            Tensor src;

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

            Cpu.CpuAllocator cpuAllocator  = new Cpu.CpuAllocator();
            long             bytesPerPixel = src.Sizes[0];

            try
            {
                using (Tensor cpuFloatTensor = new Tensor(cpuAllocator, DType.Float32, src.Sizes))
                    using (Tensor permutedFloatTensor = cpuFloatTensor.Permute(1, 2, 0))
                    {
                        Ops.Copy(cpuFloatTensor, src);
                        Ops.Mul(cpuFloatTensor, cpuFloatTensor, 255);

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



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

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

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

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

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