Hi,

I have this following code for watershed algo to segment an image. But I do not know what the error is. Can someone help me out

namespace watershed1
{
    public partial class Form1 : Form
    {
        public int X;
        public int Y;
        public int Height;
        // labels the pixel as belonging to a unique basin or as a part of the watershed line
        public int Label;
        // Distance is a work image of distances
        public int Distance;



        public Form1()
        {
            this.X = -1;
            this.Y = -1;
            this.Height = -1000;
            this.Label = -1000;
            this.Distance = -1000;
            InitializeComponent();
        }

        public Form1(int x, int y)
        {
            this.X = x;
            this.Y = y;
            this.Height = -1000;
            this.Label = WatershedCommon.INIT;
            this.Distance = 0;
        }

        public Form1(int x, int y, int height)
        {
            this.X = x;
            this.Y = y;
            this.Height = height;
            this.Label = WatershedCommon.INIT;
            this.Distance = 0;
        }

        public override bool Equals(Object obj)
        {
            Form1 p = (Form1)obj;
            return (X == p.X && X == p.Y);
        }

        public override int GetHashCode()
        {
            return X;
        }
        public override string ToString()
        {
            return "Height = " + Height + "; X = " + X.ToString() + ", Y = " + Y.ToString() +
                   "; Label = " + Label.ToString() + "; Distance = " + Distance.ToString();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog o = new OpenFileDialog();
            o.InitialDirectory = "";
            o.RestoreDirectory = true;
            if (o.ShowDialog() == DialogResult.OK)
            {
                this.pictureBox1.Image = new Bitmap(o.FileName);
                this.pictureBox1.Height = this.pictureBox1.Image.Height;
                this.pictureBox1.Width = this.pictureBox1.Image.Width;
                pictureBox1.Visible = true;
                this.Invalidate();
                this.pictureBox2.Height = this.pictureBox1.Image.Height;
                this.pictureBox2.Width = this.pictureBox1.Image.Width;
                pictureBox2.Visible = false;
                this.Invalidate();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Bitmap bmp = (Bitmap)pictureBox1.Image;
            WatershedGrayscale wg = new WatershedGrayscale(8);
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
            wg.execute(bmpdata);
            bmp.UnlockBits(bmpdata);
            pictureBox2.Image = (System.Drawing.Image)bmp;
            pictureBox1.Visible = true;
        }
    }

    public class WatershedGrayscale : FilterGrayToGray
    {
        #region Variables
        private Form1 FictitiousPixel = new Form1();
        private int _currentLabel = 0;
        private int _currentDistance = 0;
        private FifoQueue _fifoQueue = new FifoQueue();
        // each pixel can be accesesd from 2 places: a dictionary for faster direct lookup of neighbouring pixels 
        // or from a height ordered list
        // sorted array of pixels according to height
        private List<List<Form1>> _heightSortedList;
        // string in the form "X,Y" is used as a key for the dictionary lookup of a pixel
        private Dictionary<string, Form1> _pixelMap;
        private int _watershedPixelCount = 0;
        private int _numberOfNeighbours = 8;
        private bool _borderInWhite;
        private int _pictureWidth = 0;
        private int _pictureHeight = 0;
        #endregion

        #region Constructors
        public WatershedGrayscale()
            : this(8)
        { }

        public WatershedGrayscale(int numberOfNeighbours)
        {
            if (numberOfNeighbours != 8 && numberOfNeighbours != 4)
                throw new Exception("Invalid number of neighbour pixels to check. Valid values are 4 and 8.");
            _borderInWhite = true;
            _numberOfNeighbours = numberOfNeighbours;
            _heightSortedList = new List<List<Form1>>(256);
            for (int i = 0; i < 256; i++)
                _heightSortedList.Add(new List<Form1>());
        }
        #endregion

        #region Properties
        /// <summary>
        /// number of neighbours to check for each pixel. valid values are 8 and 4
        /// </summary>
        public int NumberOfNeighbours
        {
            get { return _numberOfNeighbours; }
            set
            {
                if (value != 8 && value != 4)
                    throw new Exception("Invalid number of neighbour pixels to check. Valid values are 4 and 8.");
                _numberOfNeighbours = value;
            }
        }

        /// <summary>
        /// Number of labels/basins found
        /// </summary>
        public int LabelCount
        {
            get { return _currentLabel; }
            set { _currentLabel = value; }
        }

        /// <summary>
        /// True: border is drawn in white. False: border is drawn in black
        /// </summary>
        /// <value></value>
        public bool BorderInWhite
        {
            get { return _borderInWhite; }
            set { _borderInWhite = value; }
        }
        #endregion

        private void CreatePixelMapAndHeightSortedArray(BitmapData data)
        {
            _pictureWidth = data.Width;
            _pictureHeight = data.Height;
            // pixel map holds every pixel thus size of (_pictureWidth * _pictureHeight)
            _pixelMap = new Dictionary<string, Form1>(_pictureWidth * _pictureHeight);
            unsafe
            {
                int offset = data.Stride - data.Width;
                byte* ptr = (byte*)(data.Scan0);

                // get histogram of all values in grey = height
                for (int y = 0; y < data.Height; y++)
                {
                    for (int x = 0; x < data.Width; x++, ptr++)
                    {
                        Form1 p = new Form1(x, y, *ptr);
                        // add every pixel to the pixel map
                        _pixelMap.Add(p.X.ToString() + "," + p.Y.ToString(), p);
                        _heightSortedList[*ptr].Add(p);
                    }
                    ptr += offset;
                }
            }
            this._currentLabel = 0;
        }

        private void Segment()
        {
            // Geodesic SKIZ (skeleton by influence zones) of each level height
            for (int h = 0; h < _heightSortedList.Count; h++)
            {
                // get all pixels for current height
                foreach (Form1 heightSortedPixel in _heightSortedList[h])
                {
                    heightSortedPixel.Label = WatershedCommon.MASK;
                    // for each pixel on current height get neighbouring pixels
                    List<Form1> neighbouringPixels = GetNeighbouringPixels(heightSortedPixel);
                    // initialize queue with neighbours at level h of current basins or watersheds
                    foreach (Form1 neighbouringPixel in neighbouringPixels)
                    {
                        if (neighbouringPixel.Label > 0 || neighbouringPixel.Label == WatershedCommon.WSHED)
                        {
                            heightSortedPixel.Distance = 1;
                            _fifoQueue.AddToEnd(heightSortedPixel);
                            break;
                        }
                    }
                }
                _currentDistance = 1;
                _fifoQueue.AddToEnd(FictitiousPixel);
                // extend basins
                while (true)
                {
                    Form1 p = _fifoQueue.RemoveAtFront();
                    if (p.Equals(FictitiousPixel))
                    {
                        if (_fifoQueue.IsEmpty)
                            break;
                        else
                        {
                            _fifoQueue.AddToEnd(FictitiousPixel);
                            _currentDistance++;
                            p = _fifoQueue.RemoveAtFront();
                        }
                    }
                    List<Form1> neighbouringPixels = GetNeighbouringPixels(p);
                    // labelling p by inspecting neighbours
                    foreach (Form1 neighbouringPixel in neighbouringPixels)
                    {
                        // neighbouringPixel belongs to an existing basin or to watersheds
                        // in the original algorithm the condition is:
                        //   if (neighbouringPixel.Distance < currentDistance && 
                        //      (neighbouringPixel.Label > 0 || neighbouringPixel.Label == WatershedCommon.WSHED))
                        //   but this returns incomplete borders so the this one is used                        
                        if (neighbouringPixel.Distance <= _currentDistance &&
                           (neighbouringPixel.Label > 0 || neighbouringPixel.Label == WatershedCommon.WSHED))
                        {
                            if (neighbouringPixel.Label > 0)
                            {
                                // the commented condition is also in the original algorithm 
                                // but it also gives incomplete borders
                                if (p.Label == WatershedCommon.MASK /*|| p.Label == WatershedCommon.WSHED*/)
                                    p.Label = neighbouringPixel.Label;
                                else if (p.Label != neighbouringPixel.Label)
                                {
                                    p.Label = WatershedCommon.WSHED;
                                    _watershedPixelCount++;
                                }
                            }
                            else if (p.Label == WatershedCommon.MASK)
                            {
                                p.Label = WatershedCommon.WSHED;
                                _watershedPixelCount++;
                            }
                        }
                        // neighbouringPixel is plateau pixel
                        else if (neighbouringPixel.Label == WatershedCommon.MASK && neighbouringPixel.Distance == 0)
                        {
                            neighbouringPixel.Distance = _currentDistance + 1;
                            _fifoQueue.AddToEnd(neighbouringPixel);
                        }
                    }
                }
                // detect and process new minima at height level h
                foreach (Form1 p in _heightSortedList[h])
                {
                    // reset distance to zero
                    p.Distance = 0;
                    // if true then p is inside a new minimum 
                    if (p.Label == WatershedCommon.MASK)
                    {
                        // create new label
                        _currentLabel++;
                        p.Label = _currentLabel;
                        _fifoQueue.AddToEnd(p);
                        while (!_fifoQueue.IsEmpty)
                        {
                            Form1 q = _fifoQueue.RemoveAtFront();
                            // check neighbours of q
                            List<Form1> neighbouringPixels = GetNeighbouringPixels(q);
                            foreach (Form1 neighbouringPixel in neighbouringPixels)
                            {
                                if (neighbouringPixel.Label == WatershedCommon.MASK)
                                {
                                    neighbouringPixel.Label = _currentLabel;
                                    _fifoQueue.AddToEnd(neighbouringPixel);
                                }
                            }
                        }
                    }
                }
            }
        }

        private List<Form1> GetNeighbouringPixels(Form1 centerPixel)
        {
            List<Form1> temp = new List<Form1>();
            if (_numberOfNeighbours == 8)
            {
                /*
                CP = Center pixel
                (X,Y) -- get all 8 connected 
                |-1,-1|0,-1|1,-1|
                |-1, 0| CP |1, 0|
                |-1,+1|0,+1|1,+1|
                */
                // -1, -1                
                if ((centerPixel.X - 1) >= 0 && (centerPixel.Y - 1) >= 0)
                    temp.Add(_pixelMap[(centerPixel.X - 1).ToString() + "," + (centerPixel.Y - 1).ToString()]);
                //  0, -1
                if ((centerPixel.Y - 1) >= 0)
                    temp.Add(_pixelMap[centerPixel.X.ToString() + "," + (centerPixel.Y - 1).ToString()]);
                //  1, -1
                if ((centerPixel.X + 1) < _pictureWidth && (centerPixel.Y - 1) >= 0)
                    temp.Add(_pixelMap[(centerPixel.X + 1).ToString() + "," + (centerPixel.Y - 1).ToString()]);
                // -1, 0
                if ((centerPixel.X - 1) >= 0)
                    temp.Add(_pixelMap[(centerPixel.X - 1).ToString() + "," + centerPixel.Y.ToString()]);
                //  1, 0
                if ((centerPixel.X + 1) < _pictureWidth)
                    temp.Add(_pixelMap[(centerPixel.X + 1).ToString() + "," + centerPixel.Y.ToString()]);
                // -1, 1
                if ((centerPixel.X - 1) >= 0 && (centerPixel.Y + 1) < _pictureHeight)
                    temp.Add(_pixelMap[(centerPixel.X - 1).ToString() + "," + (centerPixel.Y + 1).ToString()]);
                //  0, 1
                if ((centerPixel.Y + 1) < _pictureHeight)
                    temp.Add(_pixelMap[centerPixel.X.ToString() + "," + (centerPixel.Y + 1).ToString()]);
                //  1, 1
                if ((centerPixel.X + 1) < _pictureWidth && (centerPixel.Y + 1) < _pictureHeight)
                    temp.Add(_pixelMap[(centerPixel.X + 1).ToString() + "," + (centerPixel.Y + 1).ToString()]);
            }
            else
            {
                /*
                CP = Center pixel, N/A = not used
                (X,Y) -- get only 4 connected 
                | N/A |0,-1| N/A |
                |-1, 0| CP |+1, 0|
                | N/A |0,+1| N/A |
                */
                //  -1, 0
                if ((centerPixel.X - 1) >= 0)
                    temp.Add(_pixelMap[(centerPixel.X - 1).ToString() + "," + centerPixel.Y.ToString()]);
                //  0, -1
                if ((centerPixel.Y - 1) >= 0)
                    temp.Add(_pixelMap[centerPixel.X.ToString() + "," + (centerPixel.Y - 1).ToString()]);
                //  1, 0
                if ((centerPixel.X + 1) < _pictureWidth)
                    temp.Add(_pixelMap[(centerPixel.X + 1).ToString() + "," + centerPixel.Y.ToString()]);
                //  0, 1
                if ((centerPixel.Y + 1) < _pictureHeight)
                    temp.Add(_pixelMap[centerPixel.X.ToString() + "," + (centerPixel.Y + 1).ToString()]);
            }
            return temp;
        }

        private void DrawWatershedLines(BitmapData data)
        {
            if (_watershedPixelCount == 0)
                return;

            byte watershedColor = 255;
            if (!_borderInWhite)
                watershedColor = 0;
            unsafe
            {
                int offset = data.Stride - data.Width;
                byte* ptr = (byte*)(data.Scan0);

                for (int y = 0; y < data.Height; y++)
                {
                    for (int x = 0; x < data.Width; x++, ptr++)
                    {
                        // if the pixel in our map is watershed pixel then draw it
                        if (_pixelMap[x.ToString() + "," + y.ToString()].Label == WatershedCommon.WSHED)
                            *ptr = watershedColor;
                    }
                    ptr += offset;
                }
            }
        }

        protected override void ProcessFilter(BitmapData imageData)
        {
            CreatePixelMapAndHeightSortedArray(imageData);
            Segment();
            DrawWatershedLines(imageData);
        }

        public void execute(BitmapData imageData)
        {
            ProcessFilter(imageData);
        }
    }

    public class FifoQueue
    {
        List<Form1> queue = new List<Form1>();

        public int Count
        {
            get { return queue.Count; }
        }

        public void AddToEnd(Form1 p)
        {
            queue.Add(p);
        }

        public Form1 RemoveAtFront()
        {
            Form1 temp = queue[0];
            queue.RemoveAt(0);
            return temp;
        }

        public bool IsEmpty
        {
            get { return (queue.Count == 0); }
        }

        public override string ToString()
        {
            return base.ToString() + " Count = " + queue.Count.ToString();
        }
    }

    public class WatershedCommon
    {
        #region Constants
        public const int INIT = -1;
        public const int MASK = -2;
        public const int WSHED = 0;
        #endregion
    }
}

Recommended Answers

All 12 Replies

What error are you getting?

I am not getting any error. The problem is I was not getting an output. But I have corrected my mistake :)...

For those of you who might be needing this in the future... the mistake in the code is :
In line 92, change pictureBox1.visible = true to pictureBox2.visible = true. Such a dumb mistake on my part... But I guess you learn through ur mistakes eh ;-)

I tried to make some modification to the code, but now I am getting some error. I am not too sure about where i am going wrong. any help?

private void button2_Click(object sender, EventArgs e)
        {
            unsafe
            {
                Bitmap bmp = (Bitmap)pictureBox1.Image;
                Bitmap b2 = (Bitmap)pictureBox1.Image;
                AForge.Imaging.Filters.Grayscale a = new AForge.Imaging.Filters.Grayscale(0.2125, 0.7154, 0.0721);
                bmp = a.Apply(bmp);
                AForge.Imaging.Filters.GaussianBlur g = new GaussianBlur();
                for (int i = 0; i < 15; i++)
                {
                    g.ApplyInPlace(bmp);
                }
                WatershedGrayscale wg = new WatershedGrayscale(8);
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
                byte* p1 = (byte*)(void*)bmpdata.Scan0;
                wg.execute(bmpdata);
                bmp.Save(@"C:\users\pashok\water.jpg");
                BitmapData bmpdata2 = b2.LockBits(rect, ImageLockMode.ReadWrite, b2.PixelFormat);
                //byte* p1 = (byte*)(void*)bmpdata.Scan0;
                byte* p2 = (byte*)(void*)bmpdata2.Scan0;
                int k = 0;
                while (p1 != null)
                {
                    if (p1[0] == 255)
                    {
                        ++k;
                        p2[0]=p2[1]=p2[2]=255;
                    }
                    p1 += 1;
                    if (p1 == null)
                        break;
                    p2 += 3;
                }
                /*for (int i = 0; i < bmp.Height; i++)
                {
                    for (int j = 0; j < bmp.Width; j++)
                    {
                        if (p1[i * bmp.Width + j] == 255)
                        {
                            p2[i * bmp.Width + j] = p1[i * bmp.Width + j];
                            p2[i * bmp.Width + j + 1] = p1[i * bmp.Width + j];
                            p2[i * bmp.Width + j + 2] = p1[i * bmp.Width + j];
                        }
                    }
                }*/
                pictureBox2.Image = (System.Drawing.Image)b2;
                pictureBox2.Visible = true;
                bmp.UnlockBits(bmpdata);
                b2.UnlockBits(bmpdata2);
            }
        }

I have attached only the button event, because the rest of the code is the same as what appears above

once again, what is the error you are geting? If we know what the error is it makes it much easier to ocate the source of the problem. Lso, the Visual Studio IDE will usually highlight the line that threw the exception which will also help :)

Hi Ryshad
can you help me in this cod

Firstly, please do not resurrect old threads. This thread was resolved almsot a year ago. If you need help, post a new thread on the boards and give as much information as you can.
Secondly, I am not the only solver on the boards, there are a lot of very talented people here that will help you :)

in line 96 the class FilterGrayToGray not fond what this?

Considering this is a large and complex program someone wrote i would not recommend trying to use it for your own work. Use it for reference to learn how an element of it works, but trying to paste and run it is unlikely to help you.
The line you pointed out shows class inheritance so FilterGrayToGray is a class which is either a) in a namespace you havent referenced or b) written by the OP and not in the code listing above.

please send me full codeproject. i really need it for my final task. Thank you very much

commented: no. This is not what daniweb is for +0
commented: Please read forum rules before posting anything. -2

please send me full codeproject. i really need it for my final task. Thank you very much

@dheai

Do not hijack another thread to ask your question but start your own thread instead.

Please read the rules before posting again - http://www.daniweb.com/forums/thread78223.html and rules.

Thread Locked.

commented: Thank you..i have tried and tried to point them in the right direction : / +2
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.