Пример #1
0
        /// <summary>
        /// Constructor which takes .NET array
        /// dtype and shape is determined from array
        /// </summary>
        /// <param name="values"></param>
        /// <param name="shape"></param>
        /// <param name="order"></param>
        /// <returns>Array with values</returns>
        /// <remarks>This constructor calls <see cref="IStorage.Allocate(NumSharp.Shape,System.Type)"/></remarks>
        public NDArray(IArraySlice values, Shape shape = default, char order = 'C') : this(values.TypeCode)
        {
            if (order != 'C')
                shape.ChangeTensorLayout(order);

            if (shape.IsEmpty)
                shape = Shape.Vector((int) values.Count); //TODO! when long index, remove cast int

            Storage.Allocate(values, shape);
        }
Пример #2
0
        /// <summary>
        ///     Return a contiguous flattened array. A 1-D array, containing the elements of the input, is returned
        /// </summary>
        /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.ravel.html</remarks>
        /// <param name="a">Input array. The elements in a are read in the order specified by order, and packed as a 1-D array.</param>
        /// <remarks><br></br>If this array's <see cref="Shape"/> is a sliced or broadcasted, the a copy will be made.</remarks>
        public static NDArray ravel(NDArray a)
        {
            // ReSharper disable once ConvertIfStatementToReturnStatement
            if (!a.Shape.IsContiguous)
            {
                return(new NDArray(new UnmanagedStorage(a.Storage.CloneData(), Shape.Vector(a.size))));
            }

            return(a.reshape(Shape.Vector(a.size)));
        }
Пример #3
0
        /// <summary>
        /// Constructor which takes .NET array
        /// dtype and shape is determined from array
        /// </summary>
        /// <param name="values"></param>
        /// <param name="shape"></param>
        /// <param name="order"></param>
        /// <returns>Array with values</returns>
        /// <remarks>This constructor calls <see cref="IStorage.Allocate(NumSharp.Shape,System.Type)"/></remarks>
        public NDArray(IArraySlice values, Shape shape = default, char order = 'C') : this(values.TypeCode)
        {
            if (order != 'C')
                shape.ChangeTensorLayout(order);

            if (shape.IsEmpty)
                shape = Shape.Vector(values.Count);

            Storage.Allocate(values, shape);
        }
Пример #4
0
        /// <summary>
        /// Return evenly spaced values within a given interval.
        ///
        /// Values are generated within the half-open interval [start, stop)
        /// (in other words, the interval including start but excluding stop).
        /// For integer arguments the function is equivalent to the Python built-in
        /// range function, but returns an ndarray rather than a list.
        ///
        /// When using a non-integer step, such as 0.1, the results will often not
        /// be consistent.  It is better to use numpy.linspace for these cases.
        /// </summary>
        /// <param name="start">
        /// Start of interval.  The interval includes this value.  The default
        /// start value is 0.
        /// </param>
        /// <param name="stop">
        /// End of interval.  The interval does not include this value, except
        /// in some cases where step is not an integer and floating point
        /// round-off affects the length of out.
        /// </param>
        /// <param name="step">
        /// Spacing between values.  For any output out, this is the distance
        /// between two adjacent values, out[i+1] - out[i].  The default
        /// step size is 1.  If step is specified as a position argument,
        /// start must also be given.
        /// </param>
        /// <returns>
        /// Array of evenly spaced values.
        ///
        /// For floating point arguments, the length of the result is
        /// ceil((stop - start)/step).  Because of floating point overflow,
        /// this rule may result in the last element of out being greater
        /// than stop.
        /// </returns>
        public static NDArray arange(float start, float stop, float step = 1)
        {
            if (Math.Abs(step) < 0.000001)
            {
                throw new ArgumentException("step can't be 0", nameof(step));
            }

            bool negativeStep = false;

            if (step < 0)
            {
                negativeStep = true;
                step         = Math.Abs(step);
                //swap
                var tmp = start;
                start = stop;
                stop  = tmp;
            }

            if (start > stop)
            {
                throw new Exception("parameters invalid, start is greater than stop.");
            }


            int length = (int)Math.Ceiling((stop - start + 0.0d) / step);
            var nd     = new NDArray(typeof(float), Shape.Vector(length), false); //do not fill, we are about to

            if (negativeStep)
            {
                step = Math.Abs(step);
                unsafe
                {
                    var addr = (float *)nd.Array.Address;
                    for (int add = length - 1, i = 0; add >= 0; add--, i++)
                    {
                        addr[i] = 1 + start + add * step;
                    }
                }
            }
            else
            {
                unsafe
                {
                    var addr = (float *)nd.Array.Address;
                    for (int i = 0; i < length; i++)
                    {
                        addr[i] = start + i * step;
                    }
                }
            }

            return(nd);
        }
Пример #5
0
        /// <summary>
        ///     Return a contiguous flattened array. A 1-D array, containing the elements of the input, is returned
        /// </summary>
        /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.ravel.html</remarks>
        /// <param name="a">Input array. The elements in a are read in the order specified by order, and packed as a 1-D array.</param>
        /// <remarks><br></br>If this array's <see cref="Shape"/> is a slice, the a copy will be made.</remarks>
        public static NDArray ravel(NDArray a)
        {
            //TODO! when slice reshaping is done, prevent this cloning.
            // ReSharper disable once ConvertIfStatementToReturnStatement
            if (a.Shape.IsSliced)
            {
                return(new NDArray(new UnmanagedStorage(a.Storage.CloneData(), Shape.Vector(a.size))));
            }

            return(a.reshape(Shape.Vector(a.size)));
        }
Пример #6
0
        /// <summary>
        ///     Creates a Vector <see cref="NDArray"/> from given <paramref name="data"/>.
        /// </summary>
        /// <typeparam name="T">The type of given array, must be compliant to numpy's supported dtypes.</typeparam>
        /// <param name="data">The enumeration of data to create <see cref="NDArray"/> from.</param>
        /// <returns>An <see cref="NDArray"/> with the data and shape of the given array.</returns>
        /// <remarks>
        ///     https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html <br></br>
        ///     Always performs a copy.<br></br>
        ///     <paramref name="size"/> can be used to limit the amount of items to read form <paramref name="data"/>. Reading stops on either size or <paramref name="data"/> ends.
        /// </remarks>
        public static NDArray array <T>(IEnumerable <T> data, int size) where T : unmanaged
        {
            var slice = new ArraySlice <T>(new UnmanagedMemoryBlock <T>(size));

            unsafe
            {
                using (var enumerator = data.GetEnumerator())
                {
                    Func <bool> next = enumerator.MoveNext;

                    var addr = slice.Address;
                    for (int i = 0; i < size && next(); i++)
                    {
                        addr[i] = enumerator.Current;
                    }
                }
            }

            return(new NDArray(slice, Shape.Vector(slice.Count)));
        }
Пример #7
0
        /// <summary>
        ///     Creates <see cref="NDArray"/> from given <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="image">The image to load data from.</param>
        /// <param name="flat">
        ///     If true, returns NDArray be 1-d of pixels: `R1G1B1R2G2B2 ... RnGnBn` where n is the amount of pixels in the image.<br></br>
        ///     If false, returns a 4-d NDArray shaped: (1, bmpData.Height, bmpData.Width, 3)
        /// </param>
        /// <param name="copy">
        ///     If true, performs <see cref="Bitmap.LockBits(System.Drawing.Rectangle,System.Drawing.Imaging.ImageLockMode,System.Drawing.Imaging.PixelFormat)"/>
        ///     and then copies the data to a new <see cref="NDArray"/> then finally releasing the locked bits.<br></br>
        ///     If false, It'll call <see cref="Bitmap.LockBits(System.Drawing.Rectangle,System.Drawing.Imaging.ImageLockMode,System.Drawing.Imaging.PixelFormat)"/>
        ///     , wraps the <see cref="BitmapData.Scan0"/> with an NDArray and call <see cref="Bitmap.UnlockBits"/> only when the NDArray will be collected by the <see cref="GC"/>.
        /// </param>
        /// <returns>An NDArray that holds the pixel data of the given bitmap</returns>
        public static unsafe NDArray ToNDArray(this System.Drawing.Bitmap image, bool flat = false, bool copy = true)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }

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

            if (copy)
            {
                try
                {
                    unsafe
                    {
                        //Create a 1d vector without filling it's values to zero (similar to np.empty)
                        var nd = new NDArray(NPTypeCode.Byte, Shape.Vector(bmpData.Stride * image.Height), fillZeros: false);

                        // Get the respective addresses
                        byte *src = (byte *)bmpData.Scan0;
                        byte *dst = (byte *)nd.Unsafe.Address; //we can use unsafe because we just allocated that array and we know for sure it is contagious.

                        // Copy the RGB values into the array.
                        Buffer.MemoryCopy(src, dst, nd.size, nd.size); //faster than Marshal.Copy
                        return(nd.reshape(1, image.Height, image.Width, 3));
                    }
                }
                finally
                {
                    image.UnlockBits(bmpData);
                }
            }
            else
            {
                var nd = new NDArray(new ArraySlice <byte>(new UnmanagedMemoryBlock <byte>((byte *)bmpData.Scan0, bmpData.Stride * bmpData.Height, () => image.UnlockBits(bmpData))));
                return(flat ? nd : nd.reshape(1, bmpData.Height, bmpData.Width, 3));
            }
        }
Пример #8
0
 /// <summary>
 ///     Constructor which initialize elements with length of <paramref name="size"/>
 /// </summary>
 /// <param name="dtype">Internal data type</param>
 /// <param name="size">The size as a single dimension shape</param>
 /// <param name="fillZeros">Should set the values of the new allocation to default(dtype)? otherwise - old memory noise</param>
 /// <remarks>This constructor calls <see cref="IStorage.Allocate(NumSharp.Shape,System.Type)"/></remarks>
 public NDArray(NPTypeCode dtype, int size, bool fillZeros) : this(dtype, Shape.Vector(size), true) { }
Пример #9
0
 /// <summary>
 ///     Constructor which initialize elements with length of <paramref name="size"/>
 /// </summary>
 /// <param name="dtype">Internal data type</param>
 /// <param name="size">The size as a single dimension shape</param>
 /// <remarks>This constructor calls <see cref="IStorage.Allocate(NumSharp.Shape,System.Type)"/></remarks>
 public NDArray(NPTypeCode dtype, int size) : this(dtype, Shape.Vector(size), true) { }
Пример #10
0
 /// <summary>
 ///     Constructor which initialize elements with length of <paramref name="size"/>
 /// </summary>
 /// <param name="dtype">Internal data type</param>
 /// <param name="size">The size as a single dimension shape</param>
 /// <param name="fillZeros">Should set the values of the new allocation to default(dtype)? otherwise - old memory noise</param>
 /// <remarks>This constructor calls <see cref="IStorage.Allocate(NumSharp.Shape,System.Type)"/></remarks>
 public NDArray(Type dtype, int size, bool fillZeros) : this(dtype, Shape.Vector(size), fillZeros) { }
Пример #11
0
 public static NDArray array <T>(params T[] data) where T : unmanaged => new NDArray(ArraySlice.FromArray(data), Shape.Vector(data.Length));
Пример #12
0
        public static unsafe NDArray ToNDArray(this System.Drawing.Bitmap image, bool flat = false, bool copy = true, bool discardAlpha = false)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }

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

            if (copy)
            {
                try
                {
                    unsafe
                    {
                        //Create a 1d vector without filling it's values to zero (similar to np.empty)
                        var nd = new NDArray(NPTypeCode.Byte, Shape.Vector(bmpData.Stride * image.Height), fillZeros: false);

                        // Get the respective addresses
                        byte *src = (byte *)bmpData.Scan0;
                        byte *dst = (byte *)nd.Unsafe.Address; //we can use unsafe because we just allocated that array and we know for sure it is contagious.

                        // Copy the RGB values into the array.
                        Buffer.MemoryCopy(src, dst, bmpData.Stride * image.Height, nd.size); //faster than Marshal.Copy
                        var ret = nd.reshape(1, image.Height, image.Width, bmpData.Stride / bmpData.Width);
                        if (discardAlpha && ret.shape[3] == 4)
                        {
                            ret = ret[Slice.All, Slice.All, Slice.All, new Slice(stop: 3)];
                        }

                        return(flat && ret.ndim != 1 ? ret.flat : ret);
                    }
                }
                finally
                {
                    image.UnlockBits(bmpData);
                }
            }
            else
            {
                var ret = new NDArray(new ArraySlice <byte>(new UnmanagedMemoryBlock <byte>((byte *)bmpData.Scan0, bmpData.Stride * bmpData.Height, () => image.UnlockBits(bmpData))));

                if (flat)
                {
                    if (discardAlpha)
                    {
                        if (bmpData.Stride / bmpData.Width == 4)                                                 //1byte-per-color
                        {
                            return(ret.reshape(1, bmpData.Height, bmpData.Width, bmpData.Stride / bmpData.Width) //reshape
                                   [Slice.All, Slice.All, Slice.All, new Slice(stop: 3)]                         //slice
                                   .flat);                                                                       //flatten
                        }

                        if (bmpData.Stride / bmpData.Width == 8)                                                 //2bytes-per-color
                        {
                            return(ret.reshape(1, bmpData.Height, bmpData.Width, bmpData.Stride / bmpData.Width) //reshape
                                   [Slice.All, Slice.All, Slice.All, new Slice(stop: 6)]                         //slice
                                   .flat);                                                                       //flatten
                        }

                        throw new NotSupportedException($"Given bbp ({bmpData.Stride / bmpData.Width}) is not supported.");
                    }

                    return(ret.flat);
                }
                else
                {
                    ret = ret.reshape(1, bmpData.Height, bmpData.Width, bmpData.Stride / bmpData.Width); //reshape
                    if (discardAlpha)
                    {
                        if (ret.shape[3] == 4)                                              //1byte-per-color
                        {
                            ret = ret[Slice.All, Slice.All, Slice.All, new Slice(stop: 3)]; //slice
                        }
                        else if (ret.shape[3] == 8)                                         //2bytes-per-color
                        {
                            ret = ret[Slice.All, Slice.All, Slice.All, new Slice(stop: 6)]; //slice
                        }
                        else
                        {
                            throw new NotSupportedException($"Given bbp ({bmpData.Stride / bmpData.Width}) is not supported.");
                        }
                    }

                    return(ret);
                }
            }
        }
Пример #13
0
        /// <summary>
        ///     Converts <see cref="NDArray"/> to a <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="nd">The <see cref="NDArray"/> to copy pixels from, <see cref="Shape"/> is ignored completely. If nd.Unsafe.Shape.IsContiguous == false then a copy is made.</param>
        /// <param name="width">The height of the <see cref="Bitmap"/></param>
        /// <param name="height">The width of the <see cref="Bitmap"/></param>
        /// <param name="format">The format of the expected bitmap, Must be matching to given NDArray otherwise unexpected results might occur.</param>
        /// <returns>A <see cref="Bitmap"/></returns>
        /// <exception cref="ArgumentException">When nd.size != width*height, which means the ndarray be turned into the given bitmap size.</exception>
        public static unsafe Bitmap ToBitmap(this NDArray nd, int width, int height, PixelFormat format = PixelFormat.DontCare)
        {
            if (nd == null)
            {
                throw new ArgumentNullException(nameof(nd));
            }

            //if flat then initialize based on given format
            if (nd.ndim == 1 && format != PixelFormat.DontCare)
            {
                nd = nd.reshape(1, height, width, format.ToBytesPerPixel()); //theres a check internally for size mismatch.
            }
            if (nd.ndim != 4)
            {
                throw new ArgumentException("ndarray was expected to be of 4-dimensions, (1, bmpData.Height, bmpData.Width, bytesPerPixel)");
            }

            if (nd.shape[0] != 1)
            {
                throw new ArgumentException($"ndarray has more than one picture in it ({nd.shape[0]}) based on the first dimension.");
            }


            var bbp = nd.shape[3]; //bytes per pixel.

            if (bbp != extractFormatNumber())
            {
                throw new ArgumentException($"Given PixelFormat: {format} does not match the number of bytes per pixel in the 4th dimension of given ndarray.");
            }

            if (bbp * width * height != nd.size)
            {
                throw new ArgumentException($"The expected size does not match the size of given ndarray. (expected: {bbp * width * height}, actual: {nd.size})");
            }


            var ret     = new Bitmap(width, height, format);
            var bitdata = ret.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, format);

            try
            {
                var dst = new ArraySlice <byte>(new UnmanagedMemoryBlock <byte>((byte *)bitdata.Scan0, bitdata.Stride * bitdata.Height));
                if (nd.Shape.IsContiguous)
                {
                    nd.CopyTo(dst);
                }
                else
                {
                    MultiIterator.Assign(new UnmanagedStorage(dst, Shape.Vector(bitdata.Stride * bitdata.Height)), nd.Unsafe.Storage);
                }
            }
            finally
            {
                ret.UnlockBits(bitdata);
            }

            return(ret);

            int extractFormatNumber()
            {
                if (format == PixelFormat.DontCare)
                {
                    switch (bbp)
                    {
                    case 3:
                        format = PixelFormat.Format24bppRgb;
                        break;

                    case 4:
                        format = PixelFormat.Format32bppArgb;
                        break;

                    case 6:
                        format = PixelFormat.Format48bppRgb;
                        break;

                    case 8:
                        format = PixelFormat.Format64bppArgb;
                        break;
                    }

                    return(bbp);
                }

                return(format.ToBytesPerPixel());
            }
        }
Пример #14
0
        /// <summary>
        ///     Creates a Vector <see cref="NDArray"/> from given <paramref name="data"/>.
        /// </summary>
        /// <typeparam name="T">The type of given array, must be compliant to numpy's supported dtypes.</typeparam>
        /// <param name="data">The enumeration of data to create <see cref="NDArray"/> from.</param>
        /// <returns>An <see cref="NDArray"/> with the data and shape of the given array.</returns>
        /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html <br></br>Always performs a copy.</remarks>
        public static NDArray array <T>(IEnumerable <T> data) where T : unmanaged
        {
            var slice = ArraySlice.FromArray(data.ToArray(), false);

            return(new NDArray(slice, Shape.Vector(slice.Count)));
        }