Пример #1
0
        public OverlappingModel(Bitmap bitmap, int N, int width, int height, bool periodicInput, bool periodicOutput, int symmetry, int ground)
        {
            this.N   = N;
            FMX      = width;
            FMY      = height;
            periodic = periodicOutput;

            int SMX = bitmap.Width, SMY = bitmap.Height;

            byte[,] sample = new byte[SMX, SMY];
            colors         = new List <Color>();

            for (int y = 0; y < SMY; y++)
            {
                for (int x = 0; x < SMX; x++)
                {
                    Color color = bitmap.GetPixel(x, y);

                    int i = 0;
                    foreach (var c in colors)
                    {
                        if (c == color)
                        {
                            break;
                        }
                        i++;
                    }

                    if (i == colors.Count)
                    {
                        colors.Add(color);
                    }
                    sample[x, y] = (byte)i;
                }
            }

            int  C = colors.Count;
            long W = Stuff.Power(C, N * N);

            Func <Func <int, int, byte>, byte[]> pattern = f => {
                byte[] result = new byte[N * N];
                for (int y = 0; y < N; y++)
                {
                    for (int x = 0; x < N; x++)
                    {
                        result[x + y * N] = f(x, y);
                    }
                }
                return(result);
            };

            Func <int, int, byte[]> patternFromSample = (x, y) => pattern((dx, dy) => sample[(x + dx) % SMX, (y + dy) % SMY]);
            Func <byte[], byte[]>   rotate            = p => pattern((x, y) => p[N - 1 - y + x * N]);
            Func <byte[], byte[]>   reflect           = p => pattern((x, y) => p[N - 1 - x + y * N]);

            Func <byte[], long> index = p => {
                long result = 0, power = 1;
                for (int i = 0; i < p.Length; i++)
                {
                    result += p[p.Length - 1 - i] * power;
                    power  *= C;
                }
                return(result);
            };

            Func <long, byte[]> patternFromIndex = ind => {
                long   residue = ind, power = W;
                byte[] result = new byte[N * N];

                for (int i = 0; i < result.Length; i++)
                {
                    power /= C;
                    int count = 0;

                    while (residue >= power)
                    {
                        residue -= power;
                        count++;
                    }

                    result[i] = (byte)count;
                }

                return(result);
            };

            Dictionary <long, int> weights  = new Dictionary <long, int>();
            List <long>            ordering = new List <long>();

            for (int y = 0; y < (periodicInput ? SMY : SMY - N + 1); y++)
            {
                for (int x = 0; x < (periodicInput ? SMX : SMX - N + 1); x++)
                {
                    byte[][] ps = new byte[8][];

                    ps[0] = patternFromSample(x, y);
                    ps[1] = reflect(ps[0]);
                    ps[2] = rotate(ps[0]);
                    ps[3] = reflect(ps[2]);
                    ps[4] = rotate(ps[2]);
                    ps[5] = reflect(ps[4]);
                    ps[6] = rotate(ps[4]);
                    ps[7] = reflect(ps[6]);

                    for (int k = 0; k < symmetry; k++)
                    {
                        long ind = index(ps[k]);
                        if (weights.ContainsKey(ind))
                        {
                            weights[ind]++;
                        }
                        else
                        {
                            weights.Add(ind, 1);
                            ordering.Add(ind);
                        }
                    }
                }
            }

            T           = weights.Count;
            this.ground = (ground + T) % T;

            patterns   = new byte[T][];
            stationary = new double[T];
            propagator = new int[2 * N - 1][][][];

            int counter = 0;

            foreach (long w in ordering)
            {
                patterns[counter]   = patternFromIndex(w);
                stationary[counter] = weights[w];
                counter++;
            }

            wave    = new bool[FMX][][];
            changes = new bool[FMX][];
            for (int x = 0; x < FMX; x++)
            {
                wave[x]    = new bool[FMY][];
                changes[x] = new bool[FMY];
                for (int y = 0; y < FMY; y++)
                {
                    wave[x][y]    = new bool[T];
                    changes[x][y] = false;
                    for (int t = 0; t < T; t++)
                    {
                        wave[x][y][t] = true;
                    }
                }
            }

            Func <byte[], byte[], int, int, bool> agrees = (p1, p2, dx, dy) => {
                int xmin = dx < 0 ? 0 : dx, xmax = dx < 0 ? dx + N : N, ymin = dy < 0 ? 0 : dy, ymax = dy < 0 ? dy + N : N;
                for (int y = ymin; y < ymax; y++)
                {
                    for (int x = xmin; x < xmax; x++)
                    {
                        if (p1[x + N * y] != p2[x - dx + N * (y - dy)])
                        {
                            return(false);
                        }
                    }
                }
                return(true);
            };

            for (int x = 0; x < 2 * N - 1; x++)
            {
                propagator[x] = new int[2 * N - 1][][];
                for (int y = 0; y < 2 * N - 1; y++)
                {
                    propagator[x][y] = new int[T][];
                    for (int t = 0; t < T; t++)
                    {
                        List <int> list = new List <int>();
                        for (int t2 = 0; t2 < T; t2++)
                        {
                            if (agrees(patterns[t], patterns[t2], x - N + 1, y - N + 1))
                            {
                                list.Add(t2);
                            }
                        }
                        propagator[x][y][t] = new int[list.Count];
                        for (int c = 0; c < list.Count; c++)
                        {
                            propagator[x][y][t][c] = list[c];
                        }
                    }
                }
            }
        }
Пример #2
0
        public OverlappingModel(string name, int N, int width, int height, bool periodicInput, bool periodicOutput, int symmetry, int ground)
            : base(width, height)
        {
            this.N   = N;
            periodic = periodicOutput;

            string    resPath = $"samples/{name}";
            Texture2D texture = Resources.Load <Texture2D>(resPath);
            int       SMX     = texture.width;
            int       SMY     = texture.height;

            byte[,] sample = new byte[SMX, SMY];
            colors         = new List <Color>();

            for (int y = 0; y < SMY; y++)
            {
                for (int x = 0; x < SMX; x++)
                {
                    Color color = texture.GetPixel(x, y);

                    int i = 0;
                    foreach (var c in colors)
                    {
                        if (c == color)//为减少colors长度的操作
                        {
                            break;
                        }
                        i++;
                    }

                    if (i == colors.Count)//i==colors.Count证明遍历完colors还没有color,所以add
                    {
                        colors.Add(color);
                    }
                    sample[x, y] = (byte)i;//此xy记录color在colors位置
                }
            }

            int  C = colors.Count;
            long W = Stuff.Power(C, N * N);

            /// <summary>
            /// 根据遍历 byte[N*N] 提供的 x,y 参数代入 f 从中获取 byte 填充。
            /// </summary>
            /// <returns> N*N长度的byte[] </returns>
            /// <param name="f"> byte取样函数 </param>
            byte[] pattern(Func <int, int, byte> f)
            {
                byte[] result = new byte[N * N];
                for (int y = 0; y < N; y++)
                {
                    for (int x = 0; x < N; x++)
                    {
                        result[x + y * N] = f(x, y);
                    }
                }
                return(result);
            };
            /// <summary>
            /// 以xy为起点取长宽为N*N的色块,以xy为起点,dx,dy为宽高。
            /// </summary>
            byte[] patternFromSample(int x, int y) => pattern((dx, dy) => sample[(x + dx) % SMX, (y + dy) % SMY]);

            byte[] rotate(byte[] p) => pattern((x, y) => p[N - 1 - y + x * N]);  //向右转

            byte[] reflect(byte[] p) => pattern((x, y) => p[N - 1 - x + y * N]); //x左右翻转

            long index(byte[] p)
            {
                long result = 0;
                long power  = 1;

                for (int i = 0; i < p.Length; i++)
                {
                    result += p[p.Length - 1 - i] * power;//乘以power次方,防止index有冲突。
                    power  *= C;
                }
                return(result);
            };

            byte[] patternFromIndex(long ind)
            {
                long residue = ind;
                long power   = W;

                byte[] result = new byte[N * N];

                for (int i = 0; i < result.Length; i++)
                {
                    power /= C;
                    int count = 0;

                    while (residue >= power)
                    {
                        residue -= power;
                        count++;
                    }

                    result[i] = (byte)count;
                }

                return(result);
            };

            Dictionary <long, int> weights  = new Dictionary <long, int>();
            List <long>            ordering = new List <long>();

            //periodicInput含义,如果periodicInput周期性输入为true,那么以xy为起点的N*N色块取值到xy最,到尽头可以从原料图片colors起始(0,0)取。
            //反之,不是周期性,那么xy取最大值预留最大为max(xy)-N,因为非周期性N*N色块的xy>SMYSMX时不能从原料图片colors起始(0,0)取。
            for (int y = 0; y < (periodicInput ? SMY : SMY - N + 1); y++)
            {
                for (int x = 0; x < (periodicInput ? SMX : SMX - N + 1); x++)
                {
                    //ps:8个N*N大小的索引自sample色块
                    byte[][] ps = new byte[8][];

                    //逐渐顺时针旋转90度的四个方向 0,2,4,6
                    //逐渐对应的反射四个方向 1,3,5,7
                    ps[0] = patternFromSample(x, y);
                    ps[1] = reflect(ps[0]);
                    ps[2] = rotate(ps[0]);
                    ps[3] = reflect(ps[2]);
                    ps[4] = rotate(ps[2]);
                    ps[5] = reflect(ps[4]);
                    ps[6] = rotate(ps[4]);
                    ps[7] = reflect(ps[6]);

                    //symmetry默认值8
                    for (int k = 0; k < symmetry; k++)//对称
                    {
                        long ind = index(ps[k]);
                        if (weights.ContainsKey(ind))
                        {
                            weights[ind]++;
                        }
                        else
                        {
                            weights.Add(ind, 1);
                            ordering.Add(ind);
                        }
                    }
                }
            }

            T            = weights.Count;
            this.ground  = (ground + T) % T;
            patterns     = new byte[T][];
            base.weights = new double[T];

            int counter = 0;

            foreach (long w in ordering)
            {
                patterns[counter]     = patternFromIndex(w);
                base.weights[counter] = weights[w];
                counter++;
            }

            /// <summary>
            /// dx,dy当前p1周围其他色块坐标,判断p1和p2色块交界处像素是否一致
            /// </summary>
            bool agrees(byte[] p1, byte[] p2, int dx, int dy)
            {
                int xmin = dx < 0 ? 0 : dx;
                int xmax = dx < 0 ? dx + N : N;
                int ymin = dy < 0 ? 0 : dy;
                int ymax = dy < 0 ? dy + N : N;

                for (int y = ymin; y < ymax; y++)
                {
                    for (int x = xmin; x < xmax; x++)
                    {
                        if (p1[x + N * y] != p2[x - dx + N * (y - dy)])
                        {
                            return(false);
                        }
                    }
                }
                return(true);
            };

            propagator = new int[4][][];
            for (int d = 0; d < 4; d++)
            {
                propagator[d] = new int[T][];
                for (int t = 0; t < T; t++)
                {
                    List <int> list = new List <int>();
                    for (int t2 = 0; t2 < T; t2++)
                    {
                        if (agrees(patterns[t], patterns[t2], DX[d], DY[d]))//对d(4)个方向进行匹配,如果相邻tile的边边color一(agrees)那么说明t2添加进可匹配集合。
                        {
                            list.Add(t2);
                        }
                    }
                    //propagator记录T的4个方向相邻匹配的tile色块集合。
                    propagator[d][t] = new int[list.Count];
                    for (int c = 0; c < list.Count; c++)
                    {
                        propagator[d][t][c] = list[c];
                    }
                }
            }
        }