Example #1
0
        /// <summary>
        ///     Get a string out of a vector of chars.
        /// </summary>
        /// <param name="indices"></param>
        /// <returns></returns>
        /// <remarks>Performs a copy due to String .net-framework limitations.</remarks>
        public string GetString(params int[] indices)
        {
            unsafe
            {
                if (Shape.dimensions.Length - 1 != indices.Length)
                {
                    throw new ArgumentOutOfRangeException(nameof(indices), "GetString(int[]) can only accept coordinates that point to a vector of chars.");
                }

                Debug.Assert(typecode == NPTypeCode.Char);

                UnmanagedStorage src = Storage.GetData(indices);
                Debug.Assert(src.Shape.NDim == 1);

                if (!Shape.IsContiguous || Shape.ModifiedStrides)
                {
                    //this works faster than cloning.
                    var ret = new string('\0', src.Count);
                    fixed(char *retChars = ret)
                    {
                        var dst = new UnmanagedStorage(new ArraySlice <char>(new UnmanagedMemoryBlock <char>(retChars, ret.Length)), src.Shape.Clean());

                        MultiIterator.Assign(dst, src);
                    }

                    return(ret);
                }

                //new string always performs a copy, there is no need to keep reference to arr's unmanaged storage.
                return(new string((char *)src.Address, 0, src.Count));
            }
        }
Example #2
0
        /// <summary>
        ///     Copies values from one array to another, broadcasting as necessary.
        /// </summary>
        /// <param name="dst">The array into which values are copied.</param>
        /// <param name="src">The array from which values are copied.</param>
        /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.copyto.html</remarks>
        public static void copyto(NDArray dst, NDArray src) //todo! add where argument
        {
            if (dst == null)
            {
                throw new ArgumentNullException(nameof(dst));
            }

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

            //try to perform memory copy
            if (dst.Shape.IsContiguous && src.Shape.IsContiguous && dst.dtype == src.dtype && src.size == dst.size)
            {
                unsafe
                {
                    src.CopyTo(dst.Address);
                    return;
                }
            }

            //perform manual copy with automatic casting
            MultiIterator.Assign(dst.Storage, src.Storage);
        }
Example #3
0
        /// <summary>
        ///     Join a sequence of arrays along an existing axis.
        /// </summary>
        /// <param name="axis">The axis along which the arrays will be joined. If axis is None, arrays are flattened before use. Default is 0.</param>
        /// <param name="arrays">The arrays must have the same shape, except in the dimension corresponding to axis (the first, by default).</param>
        /// <returns>The concatenated array.</returns>
        /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.concatenate.html</remarks>
        public static NDArray concatenate(NDArray[] arrays, int axis = 0)
        {
            //What we do is we have the axis which is the only dimension that is allowed to be different
            //We need to perform a check if the dimensions actually match.
            //After we have the axis ax=1 where shape is (3,ax,3) - ax is the only dimension that can vary.
            //So if we got input of (3,5,3) and (3,1,3), we create a return shape of (3,6,3).
            //We perform the assignment by iterating a slice: (:,n,:) on src and dst where dst while n of dst grows as we iterate all arrays.

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

            if (arrays.Length == 0)
            {
                throw new ArgumentException("Value cannot be an empty collection.", nameof(arrays));
            }

            if (arrays.Length == 1)
            {
                return(arrays[0]);
            }

            var first      = arrays[0];
            var firstShape = (int[])first.shape.Clone();

            while (axis < 0)
            {
                axis = first.ndim + axis; //translate negative axis
            }
            int        i, j;
            int        axisSize = 0; //accumulated shape[axis] size for return shape.
            NPTypeCode retType  = first.GetTypeCode;

            foreach (var src in arrays)
            {
                //accumulate the concatenated axis
                var shape = src.shape;
                axisSize += shape[axis];

                if (ReferenceEquals(src, first))
                {
                    continue;
                }

                var srcType = src.GetTypeCode;

                //resolve what the return type should be and should we perform casting.
                if (first.GetTypeCode != srcType)
                {
                    if (srcType.CompareTo(retType) == 1)
                    {
                        retType = srcType;
                    }
                }

                if (shape.Length != first.ndim)
                {
                    throw new IncorrectShapeException("all the input arrays must have same number of dimensions.");
                }

                //verify the shapes are equal
                for (j = 0; j < shape.Length; j++)
                {
                    if (axis == j)
                    {
                        continue;
                    }

                    if (shape[j] != firstShape[j])
                    {
                        throw new IncorrectShapeException("all the input array dimensions except for the concatenation axis must match exactly.");
                    }
                }
            }

            //prepare return shape
            firstShape[axis] = axisSize;
            var retShape = new Shape(firstShape);

            var dst         = new NDArray(retType, retShape);
            var accessorDst = new Slice[retShape.NDim];
            var accessorSrc = new Slice[retShape.NDim];

            for (i = 0; i < accessorDst.Length; i++)
            {
                accessorSrc[i] = accessorDst[i] = Slice.All;
            }

            accessorSrc[axis] = Slice.Index(0);
            accessorDst[axis] = Slice.Index(0);

            foreach (var src in arrays)
            {
                var len = src.shape[axis];
                for (i = 0; i < len; i++)
                {
                    var writeTo   = dst[accessorDst];
                    var writeFrom = src[accessorSrc];
                    MultiIterator.Assign(writeTo.Storage, writeFrom.Storage);
                    accessorSrc[axis]++;
                    accessorDst[axis]++; //increment every step
                }

                accessorSrc[axis] = Slice.Index(0); //reset src
            }

            return(dst);
        }
Example #4
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());
            }
        }