示例#1
0
        /// <summary>
        /// 卷积,外层是乘积法则,内层是卷积
        /// </summary>
        /// <param name="core">卷积核平面</param>
        /// <param name="mode">卷积模式</param>
        /// <returns></returns>
        public Tensor Convolve(Tensor core, ConvolutionMode mode)
        {
            if (this.DimensionY != core.DimensionX)
            {
                throw new Exception("进行卷积的两个向量外层维度必须符合矩阵乘法规律");
            }
            Tensor newTensor = TensorBuilder.Empty(this.DimensionX, core.DimensionY);
            //创建一个与后续卷积结果大小相等的0矩阵
            Matrix <double> temp = this[0, 0].Convolve(core[0, 0], mode).Map(r => 0.0);

            for (int i = 0; i <= newTensor.DimensionX - 1; i++)
            {
                for (int j = 0; j <= newTensor.DimensionY - 1; j++)
                {
                    for (int k = 0; k <= this.DimensionY - 1; k++)
                    {
                        temp = temp + this[i, k].Convolve(core[k, j], mode);
                    }
                    newTensor[i, j] = temp;
                    temp            = temp.Map(r => 0.0);
                }
            }
            newTensor.OuterAct(r => r.CoerceZero(1e-15));
            return(newTensor);
        }
示例#2
0
        public static Tensor InvokeConvolutionKernel(
            ConvolutionMode mode, string name, Tensor input, Tensor filter, Tensor bias
            )
        {
            var compute = Pix2PixResources.Compute;
            var kernel  = compute.FindKernel(name);

            uint tgn_x, tgn_y, tgn_z;

            compute.GetKernelThreadGroupSizes(kernel, out tgn_x, out tgn_y, out tgn_z);

            var deconv      = (mode == ConvolutionMode.Backward);
            var outHeight   = deconv ? input.Shape[0] * 2 : input.Shape[0] / 2;
            var outWidth    = deconv ? input.Shape[1] * 2 : input.Shape[1] / 2;
            var outChannels = filter.Shape[deconv ? 2 : 3];

            Debug.Assert(outHeight % tgn_z == 0);
            Debug.Assert(outWidth % tgn_y == 0);
            Debug.Assert(outChannels % tgn_x == 0);

            var output = new Tensor(new [] { outHeight, outWidth, outChannels });

            var buffer_input  = new UnityEngine.ComputeBuffer(input.Data.Length, sizeof(float));
            var buffer_filter = new UnityEngine.ComputeBuffer(filter.Data.Length, sizeof(float));
            var buffer_bias   = new UnityEngine.ComputeBuffer(bias.Data.Length, sizeof(float));
            var buffer_output = new UnityEngine.ComputeBuffer(output.Data.Length, sizeof(float));

            buffer_input.SetData(input.Data);
            buffer_filter.SetData(filter.Data);
            buffer_bias.SetData(bias.Data);

            compute.SetInts("InputShape", input.Shape);
            compute.SetInts("FilterShape", filter.Shape);
            compute.SetInts("OutputShape", output.Shape);

            compute.SetBuffer(kernel, "Input", buffer_input);
            compute.SetBuffer(kernel, "Filter", buffer_filter);
            compute.SetBuffer(kernel, "Bias", buffer_bias);
            compute.SetBuffer(kernel, "Output", buffer_output);

            compute.Dispatch(kernel,
                             outChannels / (int)tgn_x,
                             outWidth / (int)tgn_y,
                             outHeight / (int)tgn_z
                             );

            buffer_output.GetData(output.Data);

            buffer_input.Dispose();
            buffer_filter.Dispose();
            buffer_bias.Dispose();
            buffer_output.Dispose();

            return(output);
        }
示例#3
0
 // Internal constructor
 private ConvolutionInfo(
     ConvolutionMode mode,
     int verticalPadding, int horizontalPadding,
     int verticalStride, int horizontalStride)
 {
     VerticalPadding   = verticalPadding >= 0 ? verticalPadding : throw new ArgumentOutOfRangeException(nameof(verticalPadding), "The vertical padding must be greater than or equal to 0");
     HorizontalPadding = horizontalPadding >= 0 ? horizontalPadding : throw new ArgumentOutOfRangeException(nameof(horizontalPadding), "The horizontal padding must be greater than or equal to 0");
     VerticalStride    = verticalStride >= 1 ? verticalStride : throw new ArgumentOutOfRangeException(nameof(verticalStride), "The vertical stride must be at least equal to 1");
     HorizontalStride  = horizontalStride >= 1 ? horizontalStride : throw new ArgumentOutOfRangeException(nameof(horizontalStride), "The horizontal stride must be at least equal to 1");
     Mode = mode;
 }
示例#4
0
 public static ConvolutionInfoFactory Same(
     ConvolutionMode mode = ConvolutionMode.Convolution,
     int verticalStride   = 1, int horizontalStride = 1)
 {
     return((input, kernels) =>
     {
         int
         verticalPadding = (input.Height * verticalStride - input.Height + kernels.X - verticalStride - 1) / 2 + 1,
         horizontalPadding = (input.Width * horizontalStride - input.Width + kernels.Y - horizontalStride - 1) / 2 + 1;
         return new ConvolutionInfo(mode, verticalPadding, horizontalPadding, verticalStride, horizontalStride);
     });
 }
示例#5
0
        public static Tensor InvokeConvolutionKernel(
            ConvolutionMode mode, string name, Tensor input, Tensor filter, Tensor bias
            )
        {
            var compute = ComputeAssets.Convolution;
            var kernel  = compute.FindKernel(name);

            uint tgn_x, tgn_y, tgn_z;

            compute.GetKernelThreadGroupSizes(kernel, out tgn_x, out tgn_y, out tgn_z);

            var trans = (mode == ConvolutionMode.Up);

            var outHeight = trans ? input.Shape[0] * 2 : input.Shape[0] / 2;
            var outWidth  = trans ? input.Shape[1] * 2 : input.Shape[1] / 2;
            //var outChannels = filter.Shape[trans ? 2 : 3];
            var outChannels = filter.Shape[3];

            Debug.Assert(filter.Shape[0] == 4);
            Debug.Assert(filter.Shape[1] == 4);

            Debug.Assert(outHeight % tgn_z == 0);
            Debug.Assert(outWidth % tgn_y == 0);
            //Debug.Assert(outChannels % tgn_x == 0);

            var output = new Tensor(new [] { outHeight, outWidth, outChannels });

            compute.SetInts("InputShape", input.Shape);
            compute.SetInts("FilterShape", filter.Shape);
            compute.SetInts("OutputShape", output.Shape);

            compute.SetInts("InputIndexer", CalculateIndexVector(input.Shape));
            compute.SetInts("FilterIndexer", CalculateIndexVector(filter.Shape));
            compute.SetInts("OutputIndexer", CalculateIndexVector(output.Shape));

            compute.SetBuffer(kernel, "Input", input.Buffer);
            compute.SetBuffer(kernel, "Filter", filter.Buffer);
            compute.SetBuffer(kernel, "Bias", bias.Buffer);
            compute.SetBuffer(kernel, "Output", output.Buffer);

            if (outChannels == 3)
            {
                compute.Dispatch(kernel, 1, outWidth, outHeight); // final convolution
            }
            else
            {
                compute.Dispatch(kernel, outChannels / (int)tgn_x, outWidth, outHeight);
            }

            return(output);
        }
示例#6
0
        public static Matrix <double> Convolve(this Matrix <double> a, Matrix <double> b, ConvolutionMode mode)
        {
            switch (mode)
            {
            case ConvolutionMode.Narrow:
            {
                return(a.Convolve(b, 1));
            }

            case ConvolutionMode.Wide:
            {
                Matrix <double> result = Matrix <double> .Build.Dense(a.RowCount + b.RowCount - 1, a.ColumnCount + b.ColumnCount - 1);

                var aCopy = a.Clone();
                aCopy = aCopy.Pad(b.RowCount - 1, b.RowCount - 1, b.ColumnCount - 1, b.ColumnCount - 1);
                for (int i = 0; i <= aCopy.RowCount - b.RowCount; i++)
                {
                    for (int j = 0; j <= aCopy.ColumnCount - b.ColumnCount; j++)
                    {
                        //先求hadamard积,然后求和
                        result[i, j] = aCopy.SubMatrix(i, b.RowCount, j, b.ColumnCount).PointwiseMultiply(b).RowSums().Sum();
                    }
                }
                return(result);
            }

            case ConvolutionMode.Same:
            {
                if (b.RowCount % 2 == 0 || b.ColumnCount % 2 == 0)
                {
                    throw new Exception("等宽卷积的卷积核大小必须为奇数");
                }
                Matrix <double> result = Matrix <double> .Build.Dense(a.RowCount, a.ColumnCount);

                var aCopy = a.Clone();
                aCopy = aCopy.Pad((b.RowCount - 1) / 2, (b.RowCount - 1) / 2, (b.ColumnCount - 1) / 2, (b.ColumnCount - 1) / 2);
                for (int i = 0; i <= aCopy.RowCount - b.RowCount; i++)
                {
                    for (int j = 0; j <= aCopy.ColumnCount - b.ColumnCount; j++)
                    {
                        //先求hadamard积,然后求和
                        result[i, j] = aCopy.SubMatrix(i, b.RowCount, j, b.ColumnCount).PointwiseMultiply(b).RowSums().Sum();
                    }
                }
                return(result);
            }

            default:
            {
                throw new Exception("需要从给定类型中选择");
            }
            }
        }
示例#7
0
        internal static Bitmap Convolute(this Bitmap bmp, double[,] hkernel, double[,] vkernel, ConvolutionMode mode = ConvolutionMode.RepeatEdges)
        {
            int ksize = hkernel.GetLength(0);
            int h     = bmp.Height;
            int w     = bmp.Width;

            if ((ksize * ksize != hkernel.Length) || (ksize < 3) || (ksize % 2 == 0) ||
                (ksize * ksize != vkernel.Length) || (vkernel.GetLength(0) != ksize))
            {
                throw new ArgumentException("The convolution kernels must be squared with an odd side length and must have an equal size.");
            }

            Bitmap dst = new Bitmap(w, h);

            bmp.Lock(psrc =>
                     dst.Lock(pdst =>
            {
                RGB getsrc(int x, int y)
                {
                    if ((x >= 0) && (y >= 0) && (x < w) && (y < h))
                    {
                        return(psrc[y * w + x]);
                    }
                    else if (mode == ConvolutionMode.Zero)
                    {
                        return(new RGB());
                    }
                    else if (mode == ConvolutionMode.RepeatEdges)
                    {
                        return(getsrc(x < 0 ? 0 : x >= w ? w - 1 : x, y < 0 ? 0 : y >= h ? h - 1 : y));
                    }
                    else
                    {
                        return(getsrc(x % w, y % h));
                    }
                }

                Parallel.For(0, w, x =>
                {
                    for (int y = 0; y < h; ++y)
                    {
                        double rv = 0, gv = 0, bv = 0;
                        double rh = 0, gh = 0, bh = 0;

                        for (int i = 0; i < ksize; ++i)
                        {
                            for (int j = 0; j < ksize; ++j)
                            {
                                RGB color = getsrc(x + i - ksize / 2, y + j - ksize / 2);

                                rv += vkernel[i, j] * color.Rf;
                                gv += vkernel[i, j] * color.Gf;
                                bv += vkernel[i, j] * color.Bf;

                                rh += hkernel[i, j] * color.Rf;
                                gh += hkernel[i, j] * color.Gf;
                                bh += hkernel[i, j] * color.Bf;
                            }
                        }

                        pdst[y * w + x] = new RGB
                                          (
                            Sqrt(rv * rv + rh * rh).Constrain(),
                            Sqrt(gv * gv + gh * gh).Constrain(),
                            Sqrt(bv * bv + bh * bh).Constrain()
                                          );
                    }
                });
            }));

            return(dst);
        }
示例#8
0
 public static ConvolutionInfo New(
     ConvolutionMode mode = ConvolutionMode.Convolution,
     int verticalPadding  = 0, int horizontalPadding = 0,
     int verticalStride   = 1, int horizontalStride  = 1)
 => new ConvolutionInfo(mode, verticalPadding, horizontalPadding, verticalStride, horizontalStride);
 public Tensor Convolve(Tensor core, ConvolutionMode mode)
 {
     return(null);
 }
示例#10
0
        /// <summary>
        /// Функция свёртки
        /// </summary>
        /// <param name="sourceImage">Исходное изображение</param>
        /// <param name="mode">Режим свёртки</param>
        /// <param name="channels">Каналы, над которыми проводится операция свёртки</param>
        /// <returns>
        /// Результирующее изображение
        /// </returns>
        public Image Convolution(Image sourceImage,
                                 ConvolutionMode mode = ConvolutionMode.collapse,
                                 int channels         = (Channel.BLUE | Channel.RED | Channel.GREEN))
        {
            Bitmap source = new Bitmap(sourceImage);

            //размеры фильтра
            int filterWidth  = filterMatrix.GetLength(1);
            int filterHeight = filterMatrix.GetLength(0);
            int filterOffset = (filterWidth - 1) / 2;           //смещение от центра


            if (mode == ConvolutionMode.expand)
            {
                source = (Bitmap)source.Expand(filterOffset);
            }

            //Для того, чтобы получить доступ к основные ARGB значения из Bitmap объекта мы сначала должны заблокировать Bitmap в памяти
            //Блокировка Bitmap в памяти предотвращает Garbage Collector от перемещения Bitmap объект на новое место в памяти.
            //При вызове Bitmap.LockBits метод исходный код создает экземпляр BitmapData объект из возвращаемого значения.
            BitmapData sourceData = source.LockBits(new Rectangle(0, 0,
                                                                  source.Width, source.Height),
                                                    ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);


            //BitmapData.Stride свойство представляет ряд байтов в одном растрового подряд пикселей.
            //В этом сценарии BitmapData.Stride должна быть равна ширине Bitmap в пикселях, умноженных на четыре,
            //так как каждый пиксель состоит из четырех байтов: Альфа, Красный, Зеленый и Синий.


            byte[] pixelBuffer = new byte[sourceData.Width * 4 * sourceData.Height];
            int    resWidth    = source.Width - filterOffset * 2;
            int    resHeight   = source.Height - filterOffset * 2;

            byte[] resultBuffer = new byte[resWidth * 4 * resHeight];

            //свойствл BitmapData.Scan0 BitmapData типа IntPtr представляет собой адрес памяти первого байта Bitmap
            //Использовуя Marshal.Copy метод, мы укажем адрес памяти отправной точки,
            //откуда начнём копирование байт Bitmap.

            Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);

            //Если растр был заблокирован в памяти обеспечим снятие блокировки с помощью вызова метода Bitmap.UnlockBits.
            source.UnlockBits(sourceData);

            double blue  = 0.0;
            double green = 0.0;
            double red   = 0.0;

            int calcOffset = 0;

            int byteOffset = 0;

            int byteOffset1 = 0;

            int width  = source.Width;
            int height = source.Height;


            //проходим по массиву так, чтобы маска вписалась внутрь
            for (int offsetY = filterOffset; offsetY < height - filterOffset; offsetY++)
            {
                for (int offsetX = filterOffset; offsetX < width - filterOffset; offsetX++)
                {
                    blue  = 0;
                    green = 0;
                    red   = 0;

                    byteOffset = offsetY *
                                 width * 4 +
                                 offsetX * 4;
                    byteOffset1 = (offsetY - filterOffset) * (width - 2 * filterOffset) * 4 +
                                  (offsetX - filterOffset) * 4;

                    //Инициирование цикла с отрицательными значениями упрощает реализацию концепции соседних пикселей.
                    for (int filterY = -filterOffset; filterY <= filterOffset; filterY++)
                    {
                        for (int filterX = -filterOffset; filterX <= filterOffset; filterX++)
                        {
                            //вычисляет индекс соседнего пиксела в отношении текущего пикселя.
                            calcOffset = byteOffset +
                                         (filterX * 4) +
                                         (filterY * width * 4);

                            //матрица значение применяется в качестве фактора индивидуальных цветовых компонентов соответствующих соседним пикселям.
                            //Результаты будут добавлены в итоговые переменные голубых, зеленых и красных каналов.
                            blue += (double)(pixelBuffer[calcOffset]) *
                                    filterMatrix[filterY + filterOffset,
                                                 filterX + filterOffset];


                            green += (double)(pixelBuffer[calcOffset + 1]) *
                                     filterMatrix[filterY + filterOffset,
                                                  filterX + filterOffset];


                            red += (double)(pixelBuffer[calcOffset + 2]) *
                                   filterMatrix[filterY + filterOffset,
                                                filterX + filterOffset];
                        }
                    }

                    //применяем коэффициент и добавить смещения, заданного параметром фильтра.
                    blue  = factor * blue + bias;
                    green = factor * green + bias;
                    red   = factor * red + bias;

                    //Цветовые компоненты могут содержать только значение в диапазоне от 0 до 255 включительно.
                    //Прежде, чем мы присвоить рассчитанное значение цветового компонента, мы гарантируем,
                    //что значение находится в пределах требуемого диапазона.
                    //Значения, которые превышают 255 установим на 255, а менее 0 устанавливаются в 0.
                    if (blue > 255)
                    {
                        blue = 255;
                    }
                    else if (blue < 0)
                    {
                        blue = 0;
                    }

                    if (green > 255)
                    {
                        green = 255;
                    }
                    else if (green < 0)
                    {
                        green = 0;
                    }

                    if (red > 255)
                    {
                        red = 255;
                    }
                    else if (red < 0)
                    {
                        red = 0;
                    }

                    if ((channels & Channel.BLUE) == Channel.BLUE)
                    {
                        resultBuffer[byteOffset1] = (byte)Math.Round(blue);
                    }
                    else
                    {
                        resultBuffer[byteOffset1] = pixelBuffer[byteOffset];
                    }
                    if ((channels & Channel.GREEN) == Channel.GREEN)
                    {
                        resultBuffer[byteOffset1 + 1] = (byte)Math.Round(green);
                    }
                    else
                    {
                        resultBuffer[byteOffset1 + 1] = pixelBuffer[byteOffset + 1];
                    }
                    if ((channels & Channel.RED) == Channel.RED)
                    {
                        resultBuffer[byteOffset1 + 2] = (byte)Math.Round(red);
                    }
                    else
                    {
                        resultBuffer[byteOffset1 + 2] = pixelBuffer[byteOffset + 2];
                    }
                    resultBuffer[byteOffset1 + 3] = 255;
                }
            }

            //создание нового растрового экземпляр объекта и копирование результат расчета буфера
            Bitmap resultBitmap = new Bitmap(resWidth, resHeight);


            BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
                                                                        resWidth, resHeight),
                                                          ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

            Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
            resultBitmap.UnlockBits(resultData);

            return(resultBitmap);
        }