// geodesic dilation from markers
        public static int[,] Reconstruction(int[,] markers, int[,] mask)
        {
            int[,] result = new int[markers.GetLength(0), markers.GetLength(1)];

            DMaxHeap <Pixel> heap = new DMaxHeap <Pixel>(5);

            // add markers to heap
            for (int x = 0; x < markers.GetLength(0); x++)
            {
                for (int y = 0; y < markers.GetLength(1); y++)
                {
                    if (markers[x, y] > 0 && mask[x, y] > 0)
                    {
                        Pixel p = new Pixel(x, y, Math.Min(markers[x, y], mask[x, y]));
                        heap.Add(p);
                    }
                    result[x, y] = 0;
                }
            }

            // process heap in order of value
            while (heap.Count > 0)
            {
                Pixel p = heap.Extract();
                if (p.Value <= result[p.X, p.Y]) // not a higher value than already determined
                {
                    continue;
                }
                result[p.X, p.Y] = p.Value;

                // add neighbours
                for (int i = -1; i <= 1; i++)
                {
                    for (int j = -1; j <= 1; j++)
                    {
                        int pxx = p.X + i, pxy = p.Y + j;

                        if (pxx < 0 || pxx >= markers.GetLength(0) || pxy < 0 || pxy >= markers.GetLength(1)) // no pixel
                        {
                            continue;
                        }

                        int val = Math.Min(mask[pxx, pxy], p.Value);
                        if (val == result[pxx, pxy]) // no loops of pixels adding each other
                        {
                            continue;
                        }

                        heap.Add(new Pixel(pxx, pxy, val));
                    }
                }
            }

            return(result);
        }
示例#2
0
        // separate objects that are touching
        public static bool[,] Watershed(int[,] image, decimal threshold)
        {
            bool[,] shed = new bool[image.GetLength(0), image.GetLength(1)]; // watershed mask
            int[,] dt    = DistanceTransform(image);                         // apply distance transform
            int[,] dt2   = new int[dt.GetLength(0), dt.GetLength(1)];

            // find global maximum
            int max = int.MinValue;

            for (int i = 0; i < dt.GetLength(0); i++)
            {
                for (int j = 0; j < dt.GetLength(1); j++)
                {
                    max = Math.Max(max, dt[i, j]);
                }
            }

            MPixel[,] pixels = new MPixel[dt.GetLength(0), dt.GetLength(1)]; // pixel object for each position

            for (int i = 0; i < dt.GetLength(0); i++)
            {
                for (int j = 0; j < dt.GetLength(1); j++)
                {
                    dt2[i, j] = dt[i, j] <= threshold * max ? 0 : dt[i, j]; // thresholded distance transform by parameter
                }
            }
            List <Tuple <int, int> > maxima = GetLocalMaxima(dt2); // find maxima of thresholded dt
            DMaxHeap <MPixel> heap          = new DMaxHeap <MPixel>();
            int label = 1;
            foreach (Tuple <int, int> t in maxima) // start at maxima
            {
                MPixel p = new MPixel(t.Item1, t.Item2, label++, dt[t.Item1, t.Item2]);
                heap.Add(p);
                pixels[p.X, p.Y] = p;
            }

            while (heap.Count > 0)
            {
                MPixel p      = heap.Extract();
                int[]  labels = new int[4]; // labels of neighbours
                if (p.X > 0 && pixels[p.X - 1, p.Y] != null)
                {
                    labels[0] = pixels[p.X - 1, p.Y].Label;
                }
                if (p.Y > 0 && pixels[p.X, p.Y - 1] != null)
                {
                    labels[1] = pixels[p.X, p.Y - 1].Label;
                }
                if (p.X < pixels.GetLength(0) - 1 && pixels[p.X + 1, p.Y] != null)
                {
                    labels[2] = pixels[p.X + 1, p.Y].Label;
                }
                if (p.Y < pixels.GetLength(1) - 1 && pixels[p.X, p.Y + 1] != null)
                {
                    labels[3] = pixels[p.X, p.Y + 1].Label;
                }

                Array.Sort(labels);

                int i = 0;
                while (i < 4 && labels[i] == 0) // first neighbour label
                {
                    i++;
                }

                bool same = true;
                for (; i < 3; i++)
                {
                    if (labels[i] != labels[i + 1]) // neighbours with different labels
                    {
                        same = false;
                    }
                }

                if (same && p.Label == 0) // all neighbour labels the same and current pixel's label not yet set
                {
                    p.Label = labels[3];  // give the same label as neighbours
                }
                // add all unprocessed neighbours
                MPixel newPixel;
                if (p.X > 0 && pixels[p.X - 1, p.Y] == null)
                {
                    newPixel = new MPixel(p.X - 1, p.Y, 0, dt[p.X - 1, p.Y]);
                    heap.Add(newPixel);
                    pixels[p.X - 1, p.Y] = newPixel;
                }
                if (p.Y > 0 && pixels[p.X, p.Y - 1] == null)
                {
                    newPixel = new MPixel(p.X, p.Y - 1, 0, dt[p.X, p.Y - 1]);
                    heap.Add(newPixel);
                    pixels[p.X, p.Y - 1] = newPixel;
                }
                if (p.X < pixels.GetLength(0) - 1 && pixels[p.X + 1, p.Y] == null)
                {
                    newPixel = new MPixel(p.X + 1, p.Y, 0, dt[p.X + 1, p.Y]);
                    heap.Add(newPixel);
                    pixels[p.X + 1, p.Y] = newPixel;
                }
                if (p.Y < pixels.GetLength(1) - 1 && pixels[p.X, p.Y + 1] == null)
                {
                    newPixel = new MPixel(p.X, p.Y + 1, 0, dt[p.X, p.Y + 1]);
                    heap.Add(newPixel);
                    pixels[p.X, p.Y + 1] = newPixel;
                }
            }

            // create mask from labels
            for (int x = 0; x < shed.GetLength(0); x++)
            {
                for (int y = 0; y < shed.GetLength(1); y++)
                {
                    shed[x, y] = pixels[x, y] == null || pixels[x, y].Label != 0;
                }
            }

            return(shed);
        }