Exemple #1
0
        /// <summary>
        /// does this polygon overlap with the other, within the given screen dimensions
        /// </summary>
        /// <param name="other">other polygon object</param>
        /// <param name="image_width">image width</param>
        /// <param name="image_height">image height</param>
        /// <returns></returns>
        public bool overlaps(polygon2D other, int image_width, int image_height)
        {
            int  i;
            bool retval = false;

            i = 0;
            while ((i < x_points.Count) && (retval == false))
            {
                if (other.isInside((float)x_points[i] * 1000 / image_width, (float)y_points[i] * 1000 / image_height))
                {
                    retval = true;
                }
                i++;
            }

            i = 0;
            while ((i < other.x_points.Count) && (retval == false))
            {
                if (isInside((float)other.x_points[i] * image_width / 1000, (float)other.y_points[i] * image_height / 1000))
                {
                    retval = true;
                }
                i++;
            }
            return(retval);
        }
Exemple #2
0
        /// <summary>
        /// return true if this polygon overlaps with another
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool overlaps(polygon2D other)
        {
            int  i;
            bool retval = false;

            i = 0;
            while ((i < x_points.Count) && (retval == false))
            {
                if (other.isInside((float)x_points[i], (float)y_points[i]))
                {
                    retval = true;
                }
                i++;
            }

            i = 0;
            while ((i < other.x_points.Count) && (retval == false))
            {
                if (isInside((float)other.x_points[i], (float)other.y_points[i]))
                {
                    retval = true;
                }
                i++;
            }
            return(retval);
        }
Exemple #3
0
        /// <summary>
        /// return a scaled version of the polygon
        /// </summary>
        /// <param name="factor"></param>
        /// <returns></returns>
        public polygon2D Scale(float factor)
        {
            polygon2D rescaled = new polygon2D();

            float centre_x = 0, centre_y = 0;
            getCentreOfGravity(ref centre_x, ref centre_y);

            for (int i = 0; i < x_points.Count; i++)
            {
                float dx = (float)x_points[i] - centre_x;
                float dy = (float)y_points[i] - centre_y;
                float x = (float)(centre_x + (dx * factor));
                float y = (float)(centre_y + (dy * factor));
                rescaled.Add(x, y);
            }
            return (rescaled);
        }
Exemple #4
0
        /// <summary>
        /// returns a copy of the polygon
        /// </summary>
        /// <returns></returns>
        public polygon2D Copy()
        {
            polygon2D new_poly = new polygon2D();
            new_poly.name = name;
            new_poly.type = type;
            new_poly.occupied = occupied;

            if (x_points != null)
            {
                for (int i = 0; i < x_points.Count; i++)
                {
                    float x = (float)x_points[i];
                    float y = (float)y_points[i];
                    new_poly.Add(x, y);
                }
            }
            return (new_poly);
        }
Exemple #5
0
        /// <summary>
        /// return a scaled version of the polygon
        /// </summary>
        /// <param name="factor"></param>
        /// <returns></returns>
        public polygon2D Scale(float factor)
        {
            polygon2D rescaled = new polygon2D();

            float centre_x = 0, centre_y = 0;

            getCentreOfGravity(ref centre_x, ref centre_y);

            for (int i = 0; i < x_points.Count; i++)
            {
                float dx = (float)x_points[i] - centre_x;
                float dy = (float)y_points[i] - centre_y;
                float x  = (float)(centre_x + (dx * factor));
                float y  = (float)(centre_y + (dy * factor));
                rescaled.Add(x, y);
            }
            return(rescaled);
        }
Exemple #6
0
        /// <summary>
        /// returns a copy of the polygon
        /// </summary>
        /// <returns></returns>
        public polygon2D Copy()
        {
            polygon2D new_poly = new polygon2D();

            new_poly.name     = name;
            new_poly.type     = type;
            new_poly.occupied = occupied;

            if (x_points != null)
            {
                for (int i = 0; i < x_points.Count; i++)
                {
                    float x = (float)x_points[i];
                    float y = (float)y_points[i];
                    new_poly.Add(x, y);
                }
            }
            return(new_poly);
        }
Exemple #7
0
 /// <summary>
 /// applies a perimeter inside which spots should be contained
 /// any spots outside of the perimeter are removed
 /// </summary>
 /// <param name="perimeter">polygon shape of the perimeter</param>
 public void applySpotPerimeter(polygon2D perimeter)
 {
     if (spots != null)
     {
         for (int i = spots.Count - 1; i >= 0; i--)
         {
             blob spot = (blob)spots[i];
             if (!perimeter.isInside((int)spot.x, (int)spot.y))
                 spots.RemoveAt(i);
         }
     }
 }
Exemple #8
0
        }

        /// <summary>
        /// after finding the horizontal and vertical axis of a region
        /// this removes any spots which are unlikely to lie inside the 
        /// axis of a square or rectangular region
        /// </summary>
        /// <param name="spots">list of spot features</param>
        /// <param name="shear_angle_point">angle defining the primary axis of the region</param>
        private void removeSpots(ArrayList spots,
            float[,] shear_angle_point)
        {
            if (shear_angle_point != null)
            {
                polygon2D area_perimeter = new polygon2D();

                float tx = shear_angle_point[0, 0];
                float ty = shear_angle_point[0, 1];
                float cx = shear_angle_point[1, 0];
                float cy = shear_angle_point[1, 1];
                float bx = shear_angle_point[2, 0];
                float by = shear_angle_point[2, 1];

                float dx1 = cx - tx;
                float dy1 = cy - ty;
                float dx2 = cx - bx;
                float dy2 = cy - by;

                float dx = dx1;
                if (Math.Abs(dx2) > Math.Abs(dx1)) dx = dx2;
                float dy = dy1;
                if (Math.Abs(dy2) > Math.Abs(dy1)) dy = dy2;

                // add a small border
                float x_offset = 4;
                float y_offset = 4;
                if (dx < 0) x_offset = -x_offset;
                if (dy < 0) y_offset = -y_offset;

                // create a polygon inside which the spot features are expected to lie
                area_perimeter.Add(tx + x_offset, ty + y_offset);
                area_perimeter.Add(cx + x_offset, cy + y_offset);
                area_perimeter.Add(bx + x_offset, by + y_offset);
                area_perimeter.Add(bx + (tx - cx) + x_offset, by + (ty - cy) + y_offset);

                // remove any spots outside of this perimeter
                for (int i = spots.Count - 1; i >= 0; i--)
                {
                    blob spot = (blob)spots[i];
                    if (!area_perimeter.isInside(spot.interpolated_x, spot.interpolated_y))
                        spots.RemoveAt(i);
                }
Exemple #9
0
        public void Update(ArrayList polygons)
        {
            DateTime current_t = DateTime.Now;

            // forward prediction: update the state of all tracked polygons
            UpdatePositionOrientation();

            // matching: do any of the tracked polygons match what we can currently see?
            for (int i = 0; i < polygons.Count; i++)
            {
                polygon2D poly = (polygon2D)polygons[i];

                float   poly_width  = poly.right() - poly.left();
                float   poly_height = poly.bottom() - poly.top();
                float   av_radius   = (poly_width + poly_height) / 4.0f;
                float[] orient      = poly.getOrientations();
                float[] grad        = poly.getGradients();

                if ((poly_width > minimum_dimension) &&
                    (poly_height > minimum_dimension))
                {
                    // find the centre of the polygon
                    float centre_x = 0, centre_y = 0;
                    poly.getCentreOfGravity(ref centre_x, ref centre_y);

                    // are any existing centre points close to this?
                    float min_displacement = 9999;
                    int   index            = -1;
                    for (int j = 0; j < tracked.Count; j++)
                    {
                        polygon2DTrackerData polytrack = (polygon2DTrackerData)tracked[j];

                        // exclusion zone
                        float perimeter_radius = polytrack.av_radius * 1.4f / polytrack.persistence;

                        float cx = polytrack.centre_x;
                        float dx = Math.Abs(cx - centre_x);
                        if (dx < perimeter_radius)
                        {
                            float cy = polytrack.centre_y;
                            float dy = Math.Abs(cy - centre_y);
                            if (dy < perimeter_radius)
                            {
                                float displacement = (float)Math.Sqrt((dx * dx) + (dy * dy));
                                if ((displacement < min_displacement) ||
                                    (min_displacement == 9999))
                                {
                                    min_displacement = displacement;
                                    index            = j;
                                }
                            }
                        }
                    }

                    if (index > -1)
                    {
                        polygon2DTrackerData matched = (polygon2DTrackerData)tracked[index];

                        // update the position and velocities
                        float dx = centre_x - matched.centre_x;
                        float dy = centre_y - matched.centre_y;
                        //float dorient = orient - matched.orientation;
                        TimeSpan dt_seconds = current_t.Subtract(matched.last_seen);

                        if (dt_seconds.TotalSeconds > 0)
                        {
                            // use running averages here to smooth out error
                            float momentum = 0.99f;
                            matched.vx = (matched.vx * momentum) + ((dx / (float)dt_seconds.TotalSeconds) * (1.0f - momentum));
                            matched.vy = (matched.vy * momentum) + ((dy / (float)dt_seconds.TotalSeconds) * (1.0f - momentum));
                            //matched.v_angular = ((matched.v_angular * momentum) + (dorient / (float)dt_seconds.TotalSeconds) * (1.0f - momentum));
                        }

                        matched.centre_x = centre_x;
                        matched.centre_y = centre_y;

                        for (int k = 0; k < 4; k++)
                        {
                            matched.orientation[k] = orient[k];
                        }


                        // find the closest orientation

                        /*
                         * float min_diff = 9999;
                         * int closest_index = -1;
                         * for (int k = 0; k < 4; k++)
                         * {
                         *  float diff = Math.Abs(orient[k] - matched.orientation);
                         *  if (diff < min_diff)
                         *  {
                         *      min_diff = diff;
                         *      closest_index = k;
                         *  }
                         * }
                         *
                         * // update the orientation
                         * if (closest_index > -1)
                         * {
                         *  matched.orientation = (orient[closest_index] * 0.01f) + (matched.orientation * 0.99f);
                         * }
                         */

                        matched.last_seen = current_t;
                        matched.persistence++;
                        matched.av_radius += (long)av_radius;

                        // avoid overflows
                        if (matched.persistence > 99999)
                        {
                            matched.persistence /= 2;
                            matched.av_radius   /= 2;
                        }
                    }
                    else
                    {
                        /*
                         * float min_orient = 9999;
                         * for (int k = 0; k < 4; k++)
                         * {
                         *  if (orient[k] < min_orient)
                         *  {
                         *      min_orient = orient[k];
                         *  }
                         * }
                         */

                        // add a new tracked polygon to the list
                        polygon2DTrackerData new_poly = new polygon2DTrackerData();
                        new_poly.centre_x    = centre_x;
                        new_poly.centre_y    = centre_y;
                        new_poly.orientation = orient;
                        new_poly.colour[0]   = (byte)(100 + rnd.Next(155));
                        new_poly.colour[1]   = (byte)(100 + rnd.Next(155));
                        new_poly.colour[2]   = (byte)(100 + rnd.Next(155));
                        new_poly.av_radius   = (long)av_radius;
                        tracked.Add(new_poly);
                    }
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// returns a grey scale histogram for the given image within the given perimeter region
        /// </summary>
        /// <param name="bmp">image data</param>
        /// <param name="wdth">width of the image</param>
        /// <param name="hght">height of the image</param>
        /// <param name="bytes_per_pixel">number of bytes per pixel</param>
        /// <param name="levels">histogram levels</param>
        /// <param name="perimeter">perimeter region inside which to calculate the histogram</param>
        /// <returns></returns>
        public static float[] GetGreyHistogram(byte[] bmp,
                                int wdth, int hght,
                                int bytes_per_pixel,
                                int levels,
                                polygon2D perimeter)
        {
            float[] hist = new float[levels];

            int tx = (int)perimeter.left();
            int ty = (int)perimeter.top();
            int bx = (int)perimeter.right();
            int by = (int)perimeter.bottom();

            for (int y = ty; y <= by; y++)
            {
                if ((y > -1) && (y < hght))
                {
                    for (int x = tx; x <= bx; x++)
                    {
                        if ((x > -1) && (x < wdth))
                        {
                            if (perimeter.isInside(x, y))
                            {
                                int n = ((y * wdth) + x) * bytes_per_pixel;
                                float intensity = 0;
                                for (int col = 0; col < bytes_per_pixel; col++)
                                    intensity += bmp[n + col];
                                intensity /= bytes_per_pixel;

                                int bucket = (int)Math.Round(intensity * levels / 255);
                                if (bucket >= levels) bucket = levels - 1;
                                hist[bucket]++;
                            }
                        }
                    }
                }
            }

            // normalise the histogram
            float max = 1;
            for (int level = 0; level < levels; level++)
                if (hist[level] > max) max = hist[level];

            for (int level = 0; level < levels; level++)
                hist[level] = hist[level] / max;

            return (hist);
        }
Exemple #11
0
        /// <summary>
        /// crops line features to the given perimeter shape
        /// </summary>
        /// <param name="lines">list of line features</param>
        /// <param name="perimeter">defines the shape within which lines should reside</param>
        public static ArrayList cropLines(ArrayList lines, polygon2D perimeter)
        {
            ArrayList cropped = new ArrayList();

            for (int i = 0; i < lines.Count; i++)
            {
                linefeature line1 = (linefeature)lines[i];
                if (perimeter.isInside((int)line1.x0, (int)line1.y0))
                    if (perimeter.isInside((int)line1.x1, (int)line1.y1))
                        cropped.Add(line1);
            }
            return(cropped);
        }
Exemple #12
0
 /// <summary>
 /// create a polygon from the corners
 /// </summary>
 private polygon2D createPolygon()
 {
     polygon2D new_polygon = new sluggish.utilities.polygon2D();
     for (int i = 0; i < corners.Count; i += 2)
     {
         float x = (float)corners[i];
         float y = (float)corners[i + 1];
         new_polygon.Add(x, y);
     }
     return (new_polygon);
 }
Exemple #13
0
        /// <summary>
        /// show the region within the given image
        /// </summary>
        /// <param name="bmp">image to draw into</param>
        /// <param name="image_width">width of the image</param>
        /// <param name="image_height">height of the image</param>
        /// <param name="bytes_per_pixel">number of bytes per pixel</param>
        /// <param name="line_width">line width to use when drawing</param>
        public void Show(byte[] bmp, int image_width, int image_height,
                         int bytes_per_pixel, int line_width, int style)
        {
            if (bytes_per_pixel == 3)
            {
                int[] colr = new int[3];
                colr[0] = 255;
                colr[1] = 255;
                colr[2] = 255;

                // use different colours for different types of region

                if (classification == "interesting area")
                {
                    colr[0] = 0;
                    colr[1] = 255;
                    colr[2] = 0;
                }

                if (classification == "datamatrix")
                {
                    colr[0] = 0;
                    colr[1] = 255;
                    colr[2] = 0;
                }

                if (classification == "text")
                {
                    colr[0] = 255;
                    colr[1] = 255;
                    colr[2] = 0;
                }


                /*
                if (geometry_type == "square")
                {
                    colr[0] = 0;
                    colr[1] = 255;
                    colr[2] = 255;
                }
                if (geometry_type == "triangle")
                {
                    colr[0] = 255;
                    colr[1] = 0;
                    colr[2] = 255;
                }
                */

                switch (style)
                {
                    case 0: // show boxes
                        {
                            float prev_x = 0, prev_y = 0;
                            float initial_x = -1, initial_y = 0;
                            float x = 0, y = 0;
                            for (int i = 0; i < corners.Count; i += 2)
                            {
                                x = tx + (float)corners[i];
                                y = ty + (float)corners[i + 1];

                                if (i > 0)
                                {
                                    sluggish.utilities.drawing.drawLine(
                                        bmp, image_width, image_height,
                                        (int)prev_x, (int)prev_y, (int)x, (int)y, colr[0], colr[1], colr[2],
                                        line_width, false);
                                }
                                else
                                {
                                    initial_x = x;
                                    initial_y = y;
                                }

                                prev_x = x;
                                prev_y = y;
                            }
                            if (initial_x > -1)
                            {
                                sluggish.utilities.drawing.drawLine(
                                    bmp, image_width, image_height,
                                    (int)initial_x, (int)initial_y, (int)x, (int)y, colr[0], colr[1], colr[2],
                                    line_width, false);
                            }
                            break;
                        }
                    case 1: // show colonisation
                        {
                            for (int x = tx; x < tx + width; x++)
                            {
                                for (int y = ty; y < ty + height; y++)
                                {
                                    if (shape[x - tx, y - ty])
                                    {
                                        int n = ((y * image_width) + x) * 3;
                                        for (int col = 0; col < 3; col++)
                                            bmp[n + col] = (byte)colr[col];
                                    }
                                }
                            }
                            break;
                        }
                    case 2: // show outline
                        {
                            float x = 0, y = 0;
                            float prev_x = 0;
                            float prev_y = 0;
                            for (int i = 0; i < outline.Count; i += 2)
                            {
                                x = tx + (int)outline[i];
                                y = ty + (int)outline[i + 1];

                                if (i > 0)
                                {
                                    sluggish.utilities.drawing.drawLine(
                                        bmp, image_width, image_height,
                                        (int)prev_x, (int)prev_y, (int)x, (int)y, colr[0], colr[1], colr[2],
                                        line_width, false);
                                }

                                prev_x = x;
                                prev_y = y;
                            }
                            // show corners
                            for (int i = 0; i < corners.Count; i += 2)
                            {
                                x = tx + (float)corners[i];
                                y = ty + (float)corners[i + 1];
                                if (i / 2 != highlight_corner)
                                {
                                    sluggish.utilities.drawing.drawCircle(
                                        bmp, image_width, image_height,
                                        (int)x, (int)y, 5, colr[0], colr[1], colr[2], line_width);
                                }
                                else
                                {
                                    sluggish.utilities.drawing.drawCircle(
                                        bmp, image_width, image_height,
                                        (int)x, (int)y, 5, 255, 0, 0, line_width + 1);
                                }

                            }
                            break;
                        }
                    case 3: // show orientations
                        {
                            int centre_xx = tx + centre_x;
                            int centre_yy = ty + centre_y;
                            int dx = (int)((major_axis_length / 2) * Math.Cos(orientation));
                            int dy = (int)((major_axis_length / 2) * Math.Sin(orientation));

                            sluggish.utilities.drawing.drawLine(
                                bmp, image_width, image_height,
                                centre_xx - dx, centre_yy - dy, centre_xx + dx, centre_yy + dy, colr[0], colr[1], colr[2],
                                line_width, false);

                            dx = (int)((minor_axis_length / 2) * Math.Cos(orientation - (Math.PI / 2)));
                            dy = (int)((minor_axis_length / 2) * Math.Sin(orientation - (Math.PI / 2)));

                            sluggish.utilities.drawing.drawLine(
                                bmp, image_width, image_height,
                                centre_xx - dx, centre_yy - dy, centre_xx + dx, centre_yy + dy, colr[0], colr[1], colr[2],
                                line_width, false);

                            break;
                        }
                    case 4: // binary threshold
                        {
                            if (binary_image != null)
                            {
                                for (int y = 0; y < height; y++)
                                    for (int x = 0; x < width; x++)
                                    //if (polygon.isInside(x, y))
                                    {
                                        int xx = tx + x;
                                        int yy = ty + y;
                                        int n = ((yy * image_width) + xx) * 3;
                                        for (int col = 0; col < 3; col++)
                                            if (binary_image[x, y])
                                                bmp[n + col] = (byte)255;
                                            else
                                                bmp[n + col] = (byte)0;
                                    }
                            }
                            break;
                        }
                    case 5: // background model low
                        {
                            if (binary_image != null)
                            {
                                for (int y = 0; y < height; y++)
                                    for (int x = 0; x < width; x++)
                                    {
                                        int xx = tx + x;
                                        int yy = ty + y;
                                        int n = ((yy * image_width) + xx) * 3;
                                        for (int col = 0; col < 3; col++)
                                            bmp[n + col] = (byte)background_low[x, y];
                                    }
                            }
                            break;
                        }
                    case 6: // background model high
                        {
                            if (binary_image != null)
                            {
                                for (int y = 0; y < height; y++)
                                    for (int x = 0; x < width; x++)
                                    {
                                        int xx = tx + x;
                                        int yy = ty + y;
                                        int n = ((yy * image_width) + xx) * 3;
                                        for (int col = 0; col < 3; col++)
                                            bmp[n + col] = (byte)background_high[x, y];
                                    }
                            }
                            break;
                        }
                    case 7: // polygon
                        {
                            if (polygon != null)
                            {
                                polygon.show(bmp, image_width, image_height, 255, 255, 0, 0, tx, ty);
                            }
                            break;
                        }
                    case 8: // spot responses
                        {
                            if (spot_map != null)
                            {
                                for (int y = 0; y < height; y++)
                                    for (int x = 0; x < width; x++)
                                    {
                                        if (polygon.isInside(x, y))
                                        {
                                            int xx = tx + x;
                                            int yy = ty + y;
                                            int n = ((yy * image_width) + xx) * 3;
                                            byte response_value = (byte)(spot_map[x, y] * 255);
                                            if (response_value > 30)
                                            {
                                                bmp[n] = 0;
                                                bmp[n + 1] = response_value;
                                                bmp[n + 2] = response_value;
                                            }
                                        }
                                    }
                            }
                            break;
                        }
                    case 9: // spot centres
                        {
                            if (spots != null)
                            {
                                polygon = createPolygon();
                                for (int y = 0; y < height; y++)
                                    for (int x = 0; x < width; x++)
                                    {
                                        if (polygon.isInside(x, y))
                                        {
                                            int xx = tx + x;
                                            int yy = ty + y;
                                            int n = ((yy * image_width) + xx) * 3;
                                            byte value = (byte)(spot_map[x, y] * 255);
                                            if (value > 5)
                                            {
                                                bmp[n] = value;
                                                bmp[n + 1] = 0;
                                                bmp[n + 2] = 0;
                                            }
                                        }
                                    }
                                for (int i = 0; i < spots.Count; i++)
                                {
                                    blob spot = (blob)spots[i];
                                    int n = (((ty + (int)Math.Round(spot.interpolated_y)) * image_width) + (tx + (int)Math.Round(spot.interpolated_x))) * 3;
                                    bmp[n] = (byte)255;
                                    bmp[n + 1] = (byte)255;
                                    bmp[n + 2] = (byte)255;
                                }
                            }
                            break;
                        }
                    case 10: // spots
                        {
                            if (spots != null)
                            {
                                for (int i = 0; i < spots.Count; i++)
                                {
                                    blob spot = (blob)spots[i];
                                    int x = tx + (int)Math.Round(spot.interpolated_x);
                                    int y = ty + (int)Math.Round(spot.interpolated_y);
                                    int radius = (int)Math.Round(spot.average_radius);

                                    int r = 0;
                                    int g = 255;
                                    int b = 0;
                                    if (spot.selected)
                                    {
                                        r = 255;
                                    }
                                    if (spot.touched)
                                    {
                                        r = 255;
                                        g = 0;
                                        b = 255;
                                    }

                                    sluggish.utilities.drawing.drawCircle(bmp, image_width, image_height,
                                                                            x, y, radius, r, g, b, 0);
                                }
                            }
                            break;
                        }
                    case 11: // connected points
                        {
                            if (spots != null)
                            {
                                for (int i = 0; i < spots.Count; i++)
                                {
                                    blob spot = (blob)spots[i];
                                    int x1 = tx + (int)spot.x;
                                    int y1 = ty + (int)spot.y;

                                    for (int j = 0; j < spot.neighbours.Count; j++)
                                    {
                                        blob neighbour = (blob)spot.neighbours[j];
                                        int x2 = tx + (int)neighbour.x;
                                        int y2 = ty + (int)neighbour.y;

                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height,
                                                                            x1, y1, x2, y2, 0, 255, 0,
                                                                            0, false);
                                    }
                                }
                            }
                            break;
                        }
                    case 12: // shear angle
                        {
                            if (shear_angle_point != null)
                            {
                                int x0 = tx + (int)(shear_angle_point[0, 0]);
                                int y0 = ty + (int)(shear_angle_point[0, 1]);
                                int x1 = tx + (int)(shear_angle_point[1, 0]);
                                int y1 = ty + (int)(shear_angle_point[1, 1]);
                                int x2 = tx + (int)(shear_angle_point[2, 0]);
                                int y2 = ty + (int)(shear_angle_point[2, 1]);

                                sluggish.utilities.drawing.drawLine(bmp, image_width, image_height,
                                                                    x0, y0, x1, y1, 0, 255, 0,
                                                                    0, false);
                                sluggish.utilities.drawing.drawLine(bmp, image_width, image_height,
                                                                    x1, y1, x2, y2, 0, 255, 0,
                                                                    0, false);
                            }
                            break;
                        }
                    case 13: // square/rectangle detection
                        {
                            /*
                                if (square_shape != null)
                                {
                                    int prev_x = 0;
                                    int prev_y = 0;
                                    for (int i = 0; i < square_shape.x_points.Count+1; i++)
                                    {
                                        int index = i;
                                        if (index >= square_shape.x_points.Count)
                                            index -= square_shape.x_points.Count;
                                  
                                        int x = tx + (int)square_shape.x_points[index];
                                        int y = ty + (int)square_shape.y_points[index];

                                        if (i > 0)                                
                                            sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, prev_x, prev_y, x, y, 0,255,0, 0, false);
                                
                                        prev_x = x;
                                        prev_y = y;
                                    }
                                }
                                */
                            break;
                        }

                    case 14: // edges
                        {
                            for (int i = 0; i < bmp.Length; i++)
                            {
                                int v = (int)(bmp[i] / 2.5f);
                                bmp[i] = (byte)v;
                            }

                            if (spot_radius > 0)
                            {
                                int grid_padding = 2;
                                float grid_fitting_pixels_per_index = 1.12f;
                                int edge_tracing_search_depth = 2;
                                float edge_tracing_threshold = 0.24f;
                                float suppression_radius_factor = 1.23f;
                                ArrayList horizontal_lines = null;
                                ArrayList vertical_lines = null;
                                float[] grid_spacing_horizontal = null;
                                float[] grid_spacing_vertical = null;
                                float dominant_orientation = 0;
                                float secondary_orientation = 0;
                                float shear_angle_radians = 0;
                                ArrayList horizontal_maxima = null;
                                ArrayList vertical_maxima = null;
                                polygon2D grid = fitGrid(ref horizontal_lines,
                                                         ref vertical_lines,
                                                         grid_fitting_pixels_per_index,
                                                         ref dominant_orientation,
                                                         ref secondary_orientation,
                                                         ref grid_spacing_horizontal,
                                                         ref grid_spacing_vertical,
                                                         ref horizontal_maxima,
                                                         ref vertical_maxima,
                                                         ref shear_angle_radians,
                                                         ref shear_angle_point,
                                                         grid_padding,
                                                         suppression_radius_factor,
                                                         edge_tracing_search_depth,
                                                         edge_tracing_threshold);

                                for (int i = 0; i < vertical_lines.Count; i++)
                                {
                                    linefeature line = (linefeature)vertical_lines[i];
                                    float x0 = tx + line.x0;
                                    float y0 = ty + line.y0;
                                    float x1 = tx + line.x1;
                                    float y1 = ty + line.y1;

                                    sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)x0, (int)y0, (int)x1, (int)y1, 255, 255, 0, 0, false);
                                }

                                for (int i = 0; i < horizontal_lines.Count; i++)
                                {
                                    linefeature line = (linefeature)horizontal_lines[i];
                                    float x0 = tx + line.x0;
                                    float y0 = ty + line.y0;
                                    float x1 = tx + line.x1;
                                    float y1 = ty + line.y1;

                                    sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)x0, (int)y0, (int)x1, (int)y1, 255, 255, 0, 0, false);
                                }

                                float line_length = image_height / 2;
                                float dxx = line_length * (float)Math.Sin(grid_orientation);
                                float dyy = line_length * (float)Math.Cos(grid_orientation);
                                float dxx2 = line_length * (float)Math.Sin(grid_orientation + shear_angle + (Math.PI / 2));
                                float dyy2 = line_length * (float)Math.Cos(grid_orientation + shear_angle + (Math.PI / 2));
                                float cx = tx + centre_x;
                                float cy = ty + centre_y;
                                //sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)(cx + dxx), (int)(cy + dyy), (int)(cx - dxx), (int)(cy - dyy), 255, 0, 0, 0, false);
                                //sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)(cx + dxx2), (int)(cy + dyy2), (int)(cx - dxx2), (int)(cy - dyy2), 255, 255, 255, 0, false);


                                dxx = line_length * (float)Math.Sin(grid_orientation);
                                dyy = line_length * (float)Math.Cos(grid_orientation);
                                //dxx2 = line_length * (float)Math.Sin(grid_orientation + shear_angle + (Math.PI / 2));
                                //dyy2 = line_length * (float)Math.Cos(grid_orientation + shear_angle + (Math.PI / 2));
                                dxx2 = line_length * (float)Math.Sin(grid_secondary_orientation);
                                dyy2 = line_length * (float)Math.Cos(grid_secondary_orientation);
                                cx = tx + centre_x;
                                cy = ty + centre_y;
                                //sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)(cx + dxx), (int)(cy + dyy), (int)(cx - dxx), (int)(cy - dyy), 255, 0, 0, 0, false);
                                //sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)(cx + dxx2), (int)(cy + dyy2), (int)(cx - dxx2), (int)(cy - dyy2), 255, 255, 255, 0, false);
                                sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)(cx + dxx), (int)(cy + dyy), (int)(cx), (int)(cy), 255, 0, 0, 0, false);
                                sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, (int)(cx + dxx2), (int)(cy + dyy2), (int)(cx), (int)(cy), 255, 255, 255, 0, false);

                            }

                            break;
                        }
                    case 15: // spatial frequency histogram
                        {
                            if (spatial_frequency_histogram != null)
                            {
                                // clear the image
                                for (int i = 0; i < bmp.Length; i++)
                                    bmp[i] = 0;

                                // find the maximum non zero index, so that we can scale the graph over the width of the image
                                int max_index = 1;
                                for (int d = 0; d < spatial_frequency_histogram.Length; d++)
                                    if (spatial_frequency_histogram[d] > 0.05f) max_index = d;
                                max_index += 2;
                                if (max_index >= spatial_frequency_histogram.Length)
                                    max_index = spatial_frequency_histogram.Length - 1;

                                // draw the histogram                            
                                int prev_x = 0;
                                int prev_y = image_height - 1;
                                for (int d = 0; d < max_index; d++)
                                {
                                    int x = d * (image_width - 1) / max_index;
                                    int y = image_height - 1 - (int)(spatial_frequency_histogram[d] * (image_height - 1));
                                    sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, prev_x, prev_y, x, y, 0, 255, 0, 0, false);
                                    prev_x = x;
                                    prev_y = y;
                                }
                            }
                            break;
                        }
                    case 16: // grid spacings
                        {
                            for (int i = 0; i < bmp.Length; i++)
                                bmp[i] = 0;

                            if ((spot_radius > 0) && (grid_graph_horizontal != null))
                            {
                                for (int axis = 0; axis < 2; axis++)
                                {
                                    int prev_x = 0, prev_y = 0;
                                    int start_index = 0;
                                    int end_index = 0;
                                    float[] grid_spacing = grid_graph_horizontal;
                                    if (axis == 1) grid_spacing = grid_graph_vertical;
                                    for (int i = 0; i < grid_spacing.Length; i++)
                                    {
                                        if (grid_spacing[i] > 0)
                                        {
                                            end_index = i;
                                            if (start_index == 0)
                                                start_index = i;
                                        }
                                        i++;
                                    }
                                    if (end_index > start_index)
                                    {
                                        for (int i = 0; i < grid_spacing.Length; i++)
                                        {
                                            int x = (i - start_index) * image_width / (end_index - start_index);
                                            int y = image_height - 1 - (int)(grid_spacing[i] * ((image_height - 1) / 2)) - (image_height * (1 - axis) / 2);
                                            if (i > 0)
                                                sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, prev_x, prev_y, x, y, 0, 255, 0, 0, false);
                                            prev_x = x;
                                            prev_y = y;
                                        }
                                    }
                                }
                            }

                            break;
                        }
                    case 17: // grid lines
                        {
                            if ((spot_radius > 0) && (grid_horizontal_maxima != null))
                            {
                                int line_length = width * 120 / 100;
                                float secondary_orientation = grid_secondary_orientation; // + shear_angle + (float)(Math.PI / 2);
                                for (int axis = 0; axis < 2; axis++)
                                {
                                    ArrayList grid_maxima = grid_horizontal_maxima;
                                    float orient = grid_orientation;
                                    if (axis == 1)
                                    {
                                        grid_maxima = grid_vertical_maxima;
                                        orient = secondary_orientation;
                                    }
                                    for (int i = 0; i < grid_maxima.Count; i++)
                                    {
                                        float r = (float)grid_maxima[i];
                                        int x0 = tx + centre_x + (int)(r * Math.Sin(orient));
                                        int y0 = ty + centre_y + (int)(r * Math.Cos(orient));
                                        int dx = (int)(line_length / 2 * Math.Sin(orient + (Math.PI / 2)));
                                        int dy = (int)(line_length / 2 * Math.Cos(orient + (Math.PI / 2)));
                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, x0, y0, x0 + dx, y0 + dy, 0, 255, 0, 0, false);
                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, x0, y0, x0 - dx, y0 - dy, 0, 255, 0, 0, false);
                                    }
                                }

                                /*
                                polygon2D cell = getGridCellPerimeter(10, 5,
                                                                      horizontal_maxima, vertical_maxima,
                                                                      dominant_orientation);
                                cell.show(bmp, image_width, image_height, 255, 0, 0, 0, tx, ty);
                                 */
                            }

                            break;
                        }
                    case 18:  // grid non-uniformity
                        {
                            if (polygon != null)
                            {
                                int line_length = width;
                                float secondary_orientation = grid_secondary_orientation; // + shear_angle + (float)(Math.PI / 2);
                                for (int axis = 0; axis < 2; axis++)
                                {
                                    ArrayList grid_maxima = grid_horizontal_maxima;
                                    float orient = grid_orientation;
                                    if (axis == 1)
                                    {
                                        grid_maxima = grid_vertical_maxima;
                                        orient = secondary_orientation;
                                    }
                                    for (int i = 0; i < grid_maxima.Count; i++)
                                    {
                                        float r = (float)grid_maxima[i];
                                        int x0 = tx + centre_x + (int)(r * Math.Sin(orient));
                                        int y0 = ty + centre_y + (int)(r * Math.Cos(orient));
                                        int dx = (int)(line_length / 2 * Math.Sin(orient + (Math.PI / 2)));
                                        int dy = (int)(line_length / 2 * Math.Cos(orient + (Math.PI / 2)));
                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, x0, y0, x0 + dx, y0 + dy, 255, 0, 0, 0, false);
                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, x0, y0, x0 - dx, y0 - dy, 255, 0, 0, 0, false);
                                    }
                                }

                                if (polygon.x_points.Count == 4)
                                {
                                    float x0 = (float)polygon.x_points[0];
                                    float y0 = (float)polygon.y_points[0];
                                    float x1 = (float)polygon.x_points[1];
                                    float y1 = (float)polygon.y_points[1];
                                    float x2 = (float)polygon.x_points[2];
                                    float y2 = (float)polygon.y_points[2];
                                    float x3 = (float)polygon.x_points[3];
                                    float y3 = (float)polygon.y_points[3];

                                    float dx_top = x1 - x0;
                                    float dy_top = y1 - y0;
                                    float dx_bottom = x2 - x3;
                                    float dy_bottom = y2 - y3;
                                    float dx_left = x3 - x0;
                                    float dy_left = y3 - y0;
                                    float dx_right = x2 - x1;
                                    float dy_right = y2 - y1;

                                    for (int grid_x = 0; grid_x < grid_columns; grid_x++)
                                    {
                                        float x_top = x0 + (grid_x * dx_top / grid_columns);
                                        float x_bottom = x3 + (grid_x * dx_bottom / grid_columns);
                                        float y_top = y0 + (grid_x * dy_top / grid_columns);
                                        float y_bottom = y3 + (grid_x * dy_bottom / grid_columns);
                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, tx + (int)x_top, ty + (int)y_top, tx + (int)x_bottom, ty + (int)y_bottom, 0, 255, 0, 0, false);
                                    }
                                    for (int grid_y = 0; grid_y < grid_rows; grid_y++)
                                    {
                                        float x_left = x0 + (grid_y * dx_left / grid_rows);
                                        float x_right = x1 + (grid_y * dx_right / grid_rows);
                                        float y_left = y0 + (grid_y * dy_left / grid_rows);
                                        float y_right = y1 + (grid_y * dy_right / grid_rows);
                                        sluggish.utilities.drawing.drawLine(bmp, image_width, image_height, tx + (int)x_left, ty + (int)y_left, tx + (int)x_right, ty + (int)y_right, 0, 255, 0, 0, false);
                                    }

                                }
                            }


                            break;
                        }
                    case 19:  // corner features
                        {
                            if (corner_features != null)
                            {
                                for (int i = 0; i < corner_features.Count; i += 2)
                                {
                                    int x = (int)corner_features[i];
                                    int y = (int)corner_features[i + 1];

                                    int n = ((y * image_width) + x) * 3;
                                    bmp[n] = 0;
                                    bmp[n + 1] = (byte)255;
                                    bmp[n + 2] = 0;
                                }
                            }
                            break;
                        }
                    case 20: // show segmentation responses
                        {
                            if (segmented != null)
                            {
                                for (int x = tx; x < tx + width; x++)
                                {
                                    for (int y = ty; y < ty + height; y++)
                                    {
                                        byte v = (byte)segmented[x - tx, y - ty];
                                        int n = ((y * image_width) + x) * 3;
                                        for (int col = 0; col < 3; col++) bmp[n + col] = v;
                                    }
                                }
                            }
                            break;
                        }
                    case 21: // horizontal maxima
                        {
                            int local_radius = 2;
                            int inhibitory_radius = image_width / 50;
                            int min_intensity = 500;
                            int max_intensity = 2500;
                            int image_threshold = 5;
                            int localAverageRadius = 500;
                            int difference_threshold = 35;
                            int step_size = 2;
                            int max_features_per_row = 9;
                            float average_magnitude_horizontal = 0;
                            ArrayList[] hor_maxima = image.horizontal_maxima(bmp, image_width, image_height, 3,
                                                                         max_features_per_row, local_radius, inhibitory_radius,
                                                                         min_intensity, max_intensity,
                                                                         image_threshold, localAverageRadius,
                                                                         difference_threshold, step_size,
                                                                         ref average_magnitude_horizontal);

                            if (hor_maxima != null)
                            {
                                for (int y = 0; y < image_height; y += step_size)
                                {
                                    int no_of_features = hor_maxima[y].Count;
                                    for (int i = 0; i < no_of_features; i += 2)
                                    {
                                        float x = (float)hor_maxima[y][i];
                                        float magnitude = (float)hor_maxima[y][i + 1];

                                        if (magnitude > average_magnitude_horizontal * 0.3f)
                                        {
                                            int radius = 2;

                                            int r = 0;
                                            int g = 255;
                                            int b = 0;

                                            sluggish.utilities.drawing.drawCircle(bmp, image_width, image_height,
                                                                                  (int)x, y, radius, r, g, b, 0);
                                        }
                                    }
                                }
                            }

                            float average_magnitude_vertical = 0;
                            ArrayList[] ver_maxima = image.vertical_maxima(bmp, image_width, image_height, 3,
                                                                         max_features_per_row, local_radius, inhibitory_radius,
                                                                         min_intensity, max_intensity,
                                                                         image_threshold, localAverageRadius,
                                                                         difference_threshold, step_size,
                                                                         ref average_magnitude_vertical);
                            if (ver_maxima != null)
                            {
                                for (int x = 0; x < image_width; x += step_size)
                                {
                                    int no_of_features = ver_maxima[x].Count;
                                    for (int i = 0; i < no_of_features; i += 2)
                                    {
                                        float y = (float)ver_maxima[x][i];
                                        float magnitude = (float)ver_maxima[x][i + 1];

                                        if (magnitude > average_magnitude_vertical * 0.3f)
                                        {
                                            int radius = 2;

                                            int r = 0;
                                            int g = 255;
                                            int b = 0;

                                            sluggish.utilities.drawing.drawCircle(bmp, image_width, image_height,
                                                                                  x, (int)y, radius, r, g, b, 0);
                                        }
                                    }
                                }
                            }
                            break;
                        }


                }

            }
            else sluggish.utilities.logging.EventLog.AddEvent("Can't display regions in a mono image");
        }
Exemple #14
0
        /// <summary>
        /// return true if this polygon overlaps with another
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool overlaps(polygon2D other)
        {
            int i;
            bool retval = false;

            i = 0;
            while ((i < x_points.Count) && (retval == false))
            {
                if (other.isInside((float)x_points[i],(float)y_points[i])) retval=true;
                i++;
            }

            i = 0;
            while ((i < other.x_points.Count) && (retval == false))
            {
                if (isInside((float)other.x_points[i], (float)other.y_points[i])) retval = true;
                i++;
            }
            return (retval);
        }
Exemple #15
0
        private void Snake(bool[,] binary_image, bool BlackOnWhite,
                          int max_itterations,
                          Random rnd)
        {
            bool SnakeComplete = false;

            //set the initial parameters for the snake
            prevSnakeStationaryPoints = 0;
            snakeStationary = 0;

            // itterate until the snake can get no smaller
            int i = 0;
            while ((!SnakeComplete) && (i < max_itterations))
            {
                SnakeComplete = Update(binary_image, BlackOnWhite, elasticity, gravity, rnd);
                i++;
            }

            // create a new polygon shape
            shape = new polygon2D();
            for (i = 0; i < no_of_points; i++)
                shape.Add((int)SnakePoint[i, SNAKE_X], (int)SnakePoint[i, SNAKE_Y]);
        }
Exemple #16
0
        /// <summary>
        /// returns a polygon describing the perimeter of a grid cell
        /// at the given coordinate
        /// </summary>
        /// <param name="grid_x">x grid coordinate</param>
        /// <param name="grid_y">y grid coordinate</param>
        /// <param name="horizontal_maxima">horizontal grid line positions</param>
        /// <param name="vertical_maxima">vertical grid line positions</param>
        /// <param name="dominant_orientation">oprientation of the grid pattern</param>
        /// <param name="shear angle_radians">deviation from perfectly perpendicular axes</param>
        /// <returns>polygon object for the grid cell</returns>
        private polygon2D getGridCellPerimeter(int grid_x, int grid_y,
                                               ArrayList horizontal_maxima,
                                               ArrayList vertical_maxima,
                                               float dominant_orientation,
                                               float secondary_orientation,
                                               float shear_angle_radians)
        {
            polygon2D perimeter = new polygon2D();

            float r0 = (float)horizontal_maxima[grid_y];
            float x0 = centre_x + (float)(r0 * Math.Sin(dominant_orientation));
            float y0 = centre_y + (float)(r0 * Math.Cos(dominant_orientation));

            float r1 = (float)horizontal_maxima[grid_y + 1];
            float x1 = centre_x + (float)(r1 * Math.Sin(dominant_orientation));
            float y1 = centre_y + (float)(r1 * Math.Cos(dominant_orientation));

            float r2 = (float)vertical_maxima[grid_x];
            //float secondary_orientation = dominant_orientation + 
            //                              shear_angle_radians + 
            //                              (float)(Math.PI / 2);
            float x2 = (float)(r2 * Math.Sin(secondary_orientation));
            float y2 = (float)(r2 * Math.Cos(secondary_orientation));

            float r3 = (float)vertical_maxima[grid_x + 1];
            float x3 = (float)(r3 * Math.Sin(secondary_orientation));
            float y3 = (float)(r3 * Math.Cos(secondary_orientation));

            perimeter.Add(x0 + x2, y0 + y2);
            perimeter.Add(x0 + x3, y0 + y3);
            perimeter.Add(x1 + x3, y1 + y3);
            perimeter.Add(x1 + x2, y1 + y2);

            return (perimeter);
        }
Exemple #17
0
 /// <summary>
 /// set the position of corners from the given polygon
 /// </summary>
 /// <param name="p"></param>
 public void SetCorners(polygon2D p)
 {
     corners = new ArrayList();
     for (int i = 0; i < p.x_points.Count; i++)
     {
         corners.Add((float)(p.x_points[i]));
         corners.Add((float)(p.y_points[i]));
     }
 }
Exemple #18
0
        public region(int tx, int ty,
                      int width, int height,
                      bool[,] region_image, int[,] segmented,
                      int centre_x, int centre_y,
                      ArrayList corner_features,
                      byte[] bmp_mono, int bmp_width, int bmp_height,
                      float vertex_inflation, float vertex_angular_offset,
                      int downsampling_factor)
        {
            this.tx = tx;
            this.ty = ty;
            this.width = width;
            this.height = height;
            this.centre_x = centre_x - tx;
            this.centre_y = centre_y - ty;

            shape = new bool[width, height];
            mono_image = new byte[width * height];

            if (segmented != null)
                this.segmented = new byte[width, height];

            for (int y = ty; y < ty + height; y++)
            {
                int yy = y - ty;
                int w1 = yy * width;
                int w2 = y * bmp_width;
                for (int x = tx; x < tx + width; x++)
                {
                    int xx = x - tx;

                    int xx2 = x / downsampling_factor;
                    int yy2 = y / downsampling_factor;
                    if ((xx2 < bmp_width / downsampling_factor) &&
                        (yy2 < bmp_height / downsampling_factor))
                    {
                        // downsampled position
                        int downsampled_x = x / downsampling_factor;
                        int downsampled_y = y / downsampling_factor;

                        // get the shape as a binary image
                        shape[xx, yy] = region_image[downsampled_x,
                                                     downsampled_y];

                        // copy the segmentation response
                        // this is mainly just for debugging purposes
                        if (segmented != null)
                            this.segmented[xx, yy] = (byte)segmented[downsampled_x, downsampled_y];

                        int n1 = w1 + xx;
                        int n2 = w2 + x;
                        mono_image[n1] = bmp_mono[n2];
                    }
                }
            }

            // record corner features which are inside the bounding box
            int corners_border = 10;  // a small extra border around the bounding box
            this.corner_features = new ArrayList();
            for (int i = 0; i < corner_features.Count; i += 2)
            {
                int x = (int)corner_features[i];
                int y = (int)corner_features[i + 1];
                if ((x >= tx - corners_border) && (x <= tx + width + corners_border))
                {
                    if ((y >= ty - corners_border) && (y <= ty + height + corners_border))
                    {
                        this.corner_features.Add(x);
                        this.corner_features.Add(y);
                    }
                }
            }
            //this.corner_features = corner_features;

            // trace around the outline of the shape
            int trace_downsampling = 4;
            if (width < 200) trace_downsampling = 2;
            if (width < 100) trace_downsampling = 1;
            traceOutline(trace_downsampling);

            // find corners
            int min_corner_separation = 15;
            int angular_step_size_degrees = 10;
            locateCorners(min_corner_separation,
                          2, angular_step_size_degrees);

            // detect the angle of each corner
            detectAngles();

            if (aspect_ratio > 1.3f)
                // for elongated shapes just calculate a bounding box
                // based upon minor and major axis lengths
                createCornersFromAxes();
            else
                // find corners
                fitCorners(this.corner_features, vertex_inflation, vertex_angular_offset);

            // create a polygon from the corners
            polygon = createPolygon();

            // classify the shape depending upon number of corners 
            // and angle properties
            classifyShape();
        }
Exemple #19
0
        /// <summary>
        /// returns a polygon shape based upon the corner points located
        /// </summary>
        /// <returns></returns>
        public polygon2D GetPolygon()
        {
            polygon2D poly = new polygon2D();

            for (int i = 0; i < corners.Count; i += 2)
            {
                float x = tx + (float)corners[i];
                float y = ty + (float)corners[i + 1];
                poly.Add(x, y);
            }
            return (poly);
        }
Exemple #20
0
        /// <summary>
        /// fits a grid to a region containing square or checkerboard pattern
        /// </summary>    
        /// <param name="horizontal_lines">horizontal line features detected</param>
        /// <param name="vertical_lines">vertical line features detected</param>
        /// <param name="grid_fitting_pixels_per_index">number of pixels to be represented by each index of the spacings frequency array</param>
        /// <param name="dominant_orientation">the main orientation of the region</param>
        /// <param name="secondary_orientation">orientation of the axis perpendicular (or nearly so) to the main region orientation</param>
        /// <param name="grid_spacing_horizontal">graph showing horizontal grid spacing responses</param>
        /// <param name="grid_spacing_vertical">graph showing vertical grid spacing responses</param>
        /// <param name="horizontal_maxima">horizontal grid maxima distances from the centre of the region</param>
        /// <param name="vertical_maxima">vertical grid maxima distances from the centre of the region</param>
        /// <param name="shear_angle_radians">shear angle in radians</param>
        /// <param name="shear_angle_point">points used to display the shear angle</param>
        /// <param name="grid_padding">padding cells around the perimeter of the grid</param>
        /// <param name="suppression_radius_factor">scaling factor used for non maximal suppression when finding grid spacings, typically in the range 1.0-3.0</param>
        /// <param name="edge_tracing_search_depth">when tracing along edges to build line features this defines the depth of search to use</param>
        /// <param name="edge_tracing_threshold">a threshold applied to the spot map to produce edge features</param>
        public polygon2D fitGrid(ref ArrayList horizontal_lines,
                                 ref ArrayList vertical_lines,
                                 float grid_fitting_pixels_per_index,
                                 ref float dominant_orientation,
                                 ref float secondary_orientation,
                                 ref float[] grid_spacing_horizontal,
                                 ref float[] grid_spacing_vertical,
                                 ref ArrayList horizontal_maxima,
                                 ref ArrayList vertical_maxima,
                                 ref float shear_angle_radians,
                                 ref float[,] shear_angle_point,
                                 int grid_padding,
                                 float suppression_radius_factor,
                                 int edge_tracing_search_depth,
                                 float edge_tracing_threshold)
        {
            shear_angle_radians = 0;
            polygon2D grid = new polygon2D();

            // a threshold applied to the spot map
            float edge_threshold = edge_tracing_threshold;

            // pixels per index defines the number of pixels which will be
            // represented by every index of the grid spacing array
            // This value should be proportional to the estimated spot radius
            // as previously derrived from a frequency analysis of the binary image
            //int pixels_per_index = (int)(spot_radius/2);
            //if (pixels_per_index < 1) pixels_per_index = 1;

            // pixels per index defines the number of pixels which will be
            // represented by every index of the grid spacing array
            // This value should be proportional to the estimated spot radius
            // as previously derrived from a frequency analysis of the binary image
            float pixels_per_index = (spot_radius * grid_fitting_pixels_per_index);
            if (pixels_per_index < 0.1f) pixels_per_index = 0.1f;

            // whether to use the spot map or the binary image to find edges
            // if the spot radius is too small then the spot map just looks like
            // a blur and grid spacings are hard to distinguish clearly
            float square_pattern_min_spot_radius = 3.0f;
            float spot_radius_percent = spot_radius * 100 / width;
            bool use_edges_from_binary_image = false;
            if (spot_radius < square_pattern_min_spot_radius)
                use_edges_from_binary_image = true;
            //Console.WriteLine("Spot radius = " + spot_radius_percent.ToString());

            // when tracing along edges to build line features this
            // defines the depth of search to use
            // if the spot radius is only very small (a couple of pixels)
            // we don't want to search too far, otherwise lines are inappropriately joined
            if (use_edges_from_binary_image)
                edge_tracing_search_depth = 1;  // looking for smaller features

            // detect vertical and horizontal edge features
            // this is done by applying a threshold to the spot map            

            // detect vertical lines by tracing along edges
            if (vertical_lines == null)
            {
                ArrayList[] vertical_edges = null;
                if (use_edges_from_binary_image)
                    vertical_edges = sluggish.utilities.image.detectVerticalEdges(binary_image);
                else
                    vertical_edges = sluggish.utilities.image.detectVerticalEdges(spot_map, edge_threshold);

                vertical_lines = sluggish.utilities.image.traceVerticalLines(vertical_edges, width, 2, edge_tracing_search_depth);
                vertical_lines = sluggish.utilities.image.cropLines(vertical_lines, polygon);
            }

            // detect horizontal lines by tracing along edges
            if (horizontal_lines == null)
            {
                ArrayList[] horizontal_edges = null;
                if (use_edges_from_binary_image)
                    horizontal_edges = sluggish.utilities.image.detectHorizontalEdges(binary_image);
                else
                    horizontal_edges = sluggish.utilities.image.detectHorizontalEdges(spot_map, edge_threshold);

                horizontal_lines = sluggish.utilities.image.traceHorizontalLines(horizontal_edges, width, 2, edge_tracing_search_depth);
                horizontal_lines = sluggish.utilities.image.cropLines(horizontal_lines, polygon);
            }

            // find the dominant orientation
            // best vertical orientation
            float score_vertical = 0;
            float orientation_vertical = sluggish.utilities.image.getDominantOrientation(vertical_lines, 1, ref score_vertical);

            // best horizontal orientation
            float score_horizontal = 0;
            float orientation_horizontal = sluggish.utilities.image.getDominantOrientation(horizontal_lines, 2, ref score_horizontal);

            // choose the orientation with the strongest response
            dominant_orientation = orientation_vertical;
            secondary_orientation = orientation_horizontal;
            if (score_horizontal > score_vertical)
            {
                dominant_orientation = orientation_horizontal - (float)(Math.PI / 2);
                secondary_orientation = orientation_horizontal;

                //dominant_orientation = orientation_horizontal;
                //secondary_orientation = orientation_vertical;
            }


            // keep the orientation within the range -PI/2 - PI/2
            // so that it's always pointing "up"
            if (dominant_orientation > Math.PI / 2)
                dominant_orientation -= (float)Math.PI;
            if (dominant_orientation < -Math.PI / 2)
                dominant_orientation += (float)Math.PI;

            // calculate shear angle
            shear_angle_radians = orientation_vertical - orientation_horizontal;
            if (shear_angle_radians > 0)
                shear_angle_radians -= (float)(Math.PI / 2);
            else
                shear_angle_radians += (float)(Math.PI / 2);

            // create an array to store interceptions with the dominant axis
            grid_spacing_horizontal = new float[(int)Math.Round(width * 2 / pixels_per_index)];
            grid_spacing_vertical = new float[(int)Math.Round(width * 2 / pixels_per_index)];

            // find interception points between lines and the dominant axis
            int x0, y0, x1, y1;
            float dxx, dyy;            // vector in the dominant orientation
            float dxx2, dyy2;          // vector perpendicular to the dominant orientation
            float line_length = 1000;  // some arbitrary length - really all that we're interested in is the orientation
            float[] grid_spacing = null;
            ArrayList lines = null;
            for (int axis = 0; axis < 2; axis++)
            {
                if (axis == 0)
                {
                    lines = horizontal_lines;
                    grid_spacing = grid_spacing_horizontal;
                    // vector in the dominant orientation
                    dxx = line_length * (float)Math.Sin(dominant_orientation);
                    dyy = line_length * (float)Math.Cos(dominant_orientation);
                    // vector perpendicular to the dominant orientation
                    dxx2 = line_length * (float)Math.Sin(dominant_orientation + (Math.PI / 2));
                    dyy2 = line_length * (float)Math.Cos(dominant_orientation + (Math.PI / 2));
                }
                else
                {
                    lines = vertical_lines;
                    grid_spacing = grid_spacing_vertical;
                    // vector in the dominant orientation
                    dxx = line_length * (float)Math.Sin(dominant_orientation + (Math.PI / 2));
                    dyy = line_length * (float)Math.Cos(dominant_orientation + (Math.PI / 2));
                    // vector perpendicular to the dominant orientation
                    dxx2 = line_length * (float)Math.Sin(dominant_orientation);
                    dyy2 = line_length * (float)Math.Cos(dominant_orientation);
                }

                // coordinates for a line along the axis                
                x0 = (int)(centre_x + dxx);
                y0 = (int)(centre_y + dyy);
                x1 = (int)(centre_x - dxx);
                y1 = (int)(centre_y - dyy);

                float histogram_max = 0;
                for (int i = 0; i < lines.Count; i++)
                {
                    linefeature line = (linefeature)lines[i];

                    for (int j = 0; j < 5; j++)
                    {
                        // use the start and end points of the line
                        float px = line.x0;
                        float py = line.y0;
                        switch (j)
                        {
                            case 1:
                                {
                                    px = line.x1;
                                    py = line.y1;
                                    break;
                                }
                            case 2:
                                {
                                    px = line.x0 + ((line.x1 - line.x0) / 2);
                                    py = line.y0 + ((line.y1 - line.y0) / 2);
                                    break;
                                }
                            case 3:
                                {
                                    px = line.x0 + ((line.x1 - line.x0) / 4);
                                    py = line.y0 + ((line.y1 - line.y0) / 4);
                                    break;
                                }
                            case 4:
                                {
                                    px = line.x0 + ((line.x1 - line.x0) * 3 / 4);
                                    py = line.y0 + ((line.y1 - line.y0) * 3 / 4);
                                    break;
                                }
                        }

                        // locate intersection
                        float ix = 0, iy = 0; // intersection coordinate
                        sluggish.utilities.geometry.intersection(x0, y0, x1, y1,
                                                                 px, py,
                                                                 px + dxx2, py + dyy2,
                                                                 ref ix, ref iy);

                        if (ix != 9999)
                        {
                            // measure the distance of the intersection point from
                            // the centre of the region
                            float dx = ix - centre_x;
                            float dy = iy - centre_y;
                            float dist = (float)Math.Sqrt((dx * dx) + (dy * dy));
                            if (dist < width)
                            {
                                if (((axis == 0) && (dy < 0)) ||
                                    ((axis == 1) && (dx < 0)))
                                    dist = -dist;

                                int index = (int)Math.Round((dist / (float)pixels_per_index) + (grid_spacing.Length / 2.0f));
                                if (index >= grid_spacing.Length)
                                    index = grid_spacing.Length - 1;

                                grid_spacing[index]++;

                                if (grid_spacing[index] > histogram_max)
                                    histogram_max = grid_spacing[index];
                            }
                        }
                    }
                }

                if (histogram_max > 0)
                {
                    for (int j = 0; j < grid_spacing.Length; j++)
                        grid_spacing[j] /= histogram_max;
                }
            }

            // locate maxima within the horizontal and vertical graphs            
            float min_grid_threshold = 0.2f;
            int equalisation_steps = 3;
            equaliseGridAxes(ref horizontal_maxima, ref vertical_maxima,
                             grid_spacing_horizontal,
                             grid_spacing_vertical,
                             pixels_per_index, grid_padding,
                             suppression_radius_factor,
                             equalisation_steps,
                             min_grid_threshold);

            return (grid);
        }
Exemple #21
0
        /// <summary>
        /// after finding the horizontal and vertical axis of a region
        /// this removes any spots which are unlikely to lie inside the 
        /// axis of a square or rectangular region
        /// </summary>
        /// <param name="spots">list of spot features</param>
        /// <param name="shear_angle_point">angle defining the primary axis of the region</param>
        /// <param name="spot_culling_threshold">the ratio of possible out of bounds spots to the total number of spots must be below this threshold in order for out of bounds cases to be removed</param>
        private void removeSpots(ArrayList spots,
                                 float[,] shear_angle_point,
                                 float spot_culling_threshold)
        {
            if (shear_angle_point != null)
            {
                polygon2D area_perimeter = new polygon2D();

                float tx = shear_angle_point[0, 0];
                float ty = shear_angle_point[0, 1];
                float cx = shear_angle_point[1, 0];
                float cy = shear_angle_point[1, 1];
                float bx = shear_angle_point[2, 0];
                float by = shear_angle_point[2, 1];

                float dx1 = cx - tx;
                float dy1 = cy - ty;
                float dx2 = cx - bx;
                float dy2 = cy - by;

                float dx = dx1;
                if (Math.Abs(dx2) > Math.Abs(dx1)) dx = dx2;
                float dy = dy1;
                if (Math.Abs(dy2) > Math.Abs(dy1)) dy = dy2;

                // add a small border
                float x_offset = 4;
                float y_offset = 4;
                if (dx < 0) x_offset = -x_offset;
                if (dy < 0) y_offset = -y_offset;

                // create a polygon inside which the spot features are expected to lie
                area_perimeter.Add(tx + x_offset, ty + y_offset);
                area_perimeter.Add(cx + x_offset, cy + y_offset);
                area_perimeter.Add(bx + x_offset, by + y_offset);
                area_perimeter.Add(bx + (tx - cx) + x_offset, by + (ty - cy) + y_offset);

                // remove any spots outside of this perimeter
                ArrayList potential_victims = new ArrayList();
                for (int i = spots.Count - 1; i >= 0; i--)
                {
                    blob spot = (blob)spots[i];
                    if (!area_perimeter.isInside(spot.interpolated_x, spot.interpolated_y))
                    {
                        // add the index of this spot to the list of potential victims <evil laughter>
                        potential_victims.Add(i);
                    }
                }

                if (potential_victims.Count > 0)
                {
                    // what fraction of the spots are potential victims?
                    // if this ratio is too large then perhaps we have made a dreadful mistake!
                    float victims_ratio = potential_victims.Count / (float)spots.Count;

                    if (victims_ratio < spot_culling_threshold)
                    {
                        // let the slaughter commence
                        for (int i = 0; i < potential_victims.Count; i++)
                        {
                            int victim_index = (int)potential_victims[i];
                            spots.RemoveAt(victim_index);
                        }
                    }
                }
            }
        }
Exemple #22
0
        /// <summary>
        /// fits a grid to a region containing spot features
        /// </summary> 
        /// <param name="spots">list of detected spot features</param>
        /// <param name="max_distance">the maximum perpendicular distance below which the spot is considered to touch the line, in the range, typically in the range 0.0-1.0 as a fraction of the spot radius</param>
        /// <param name="connection_radius">radius within which spots are considered to be neighbours, typically in the range 2.0-3.0</param>
        /// <param name="grid_fitting_pixels_per_index">number of pixels to be represented by each index of the spacings frequency array</param>
        /// <param name="dominant_orientation">the main orientation of the region</param>
        /// <param name="secondary_orientation">orientation perpendicular (or nearly so) to the dominant orientation</param>
        /// <param name="grid_spacing_horizontal">graph showing horizontal grid spacing responses</param>
        /// <param name="grid_spacing_vertical">graph showing vertical grid spacing responses</param>
        /// <param name="horizontal_maxima">horizontal grid maxima distances from the centre of the region</param>
        /// <param name="vertical_maxima">vertical grid maxima distances from the centre of the region</param>
        /// <param name="shear_angle_radians">difference from perfectly perpendicular axes</param>
        /// <param name="shear_angle_point">points used to display the shear angle</param>
        /// <param name="grid_padding">padding cells around the perimeter of the grid</param>
        /// <param name="supression_radius_factor">scaling factor used to adjust non-maximal suppression radius when finding grid spacings, typically in the range 1.0-3.0</param>
        /// <param name="orientation_tollerance">maximum deviation from the preferred orientation when finding the main axis</param>
        /// <param name="spot_culling_threshold">threshold used to remove possible out of bounds spots, in the range 0.0 - 1.0</param>
        public polygon2D fitGrid(ArrayList spots, float max_distance,
                                 float connection_radius,
                                 float grid_fitting_pixels_per_index,
                                 ref float dominant_orientation,
                                 ref float secondary_orientation,
                                 ref float[] grid_spacing_horizontal,
                                 ref float[] grid_spacing_vertical,
                                 ref ArrayList horizontal_maxima,
                                 ref ArrayList vertical_maxima,
                                 ref float shear_angle_radians,
                                 ref float[,] shear_angle_point,
                                 int grid_padding,
                                 float supression_radius_factor,
                                 float orientation_tollerance,
                                 float spot_culling_threshold)
        {
            polygon2D grid = new polygon2D();

            // connect neighbouring spots
            if (spots != null)
            {
                for (int i = 0; i < spots.Count - 1; i++)
                {
                    blob spot1 = (blob)spots[i];
                    float neighbour_radius = spot1.average_radius * connection_radius;
                    for (int j = i + 1; j < spots.Count; j++)
                    {
                        blob spot2 = (blob)spots[j];
                        if (spot1.AddNeighbour(spot2, neighbour_radius))
                        {
                            spot2.AddNeighbour(spot1, neighbour_radius);
                        }
                    }
                }
            }

            // find the maximum number of aligned spots
            ArrayList spots_aligned = null;
            float preferred_orientation = -1;
            float line_centre_x0 = 0;
            float line_centre_y0 = 0;
            polynomial best_fit_line = fitLineToSpots(spots, false,
                                                      ref spots_aligned,
                                                      preferred_orientation,
                                                      orientation_tollerance,
                                                      max_distance,
                                                      ref line_centre_x0,
                                                      ref line_centre_y0);
            if (best_fit_line != null)
            {
                // find the orientation of the best fit line
                float sample_x = 100;
                float sample_y = best_fit_line.RegVal(sample_x);
                float hyp = (float)Math.Sqrt((sample_x * sample_x) + (sample_y * sample_y));
                dominant_orientation = (float)Math.Asin(sample_x / hyp);
                if (sample_y < 0) dominant_orientation = (float)(Math.PI * 2) - dominant_orientation;
                float orient = dominant_orientation;

                // if the main orientation discovered is horizontally
                // oriented then rotate it into a vertical orientation
                //bool dominant_orientation_horizontal = false;
                if (sample_x > Math.Abs(sample_y))
                {
                    //dominant_orientation_horizontal = true; 
                    dominant_orientation -= (float)(Math.PI / 2);
                }

                // always point downwards
                if (hyp * Math.Cos(dominant_orientation) < 0)
                    dominant_orientation -= (float)Math.PI;

                orientation = dominant_orientation;

                // orientation perpendicular (or nearly perpendicular) to the
                // dominant orientation
                secondary_orientation = dominant_orientation +
                                        (float)(Math.PI / 2);


                // find the second maximum number of aligned spots
                ArrayList second_spots_aligned = null;
                preferred_orientation = orient + (float)(Math.PI / 2);
                if (preferred_orientation > (float)(Math.PI * 2))
                    preferred_orientation -= (float)(Math.PI * 2);

                float line_centre_x1 = 0;
                float line_centre_y1 = 0;
                polynomial second_best_fit_line = fitLineToSpots(spots, true,
                                                                 ref second_spots_aligned,
                                                                 preferred_orientation,
                                                                 orientation_tollerance,
                                                                 max_distance,
                                                                 ref line_centre_x1,
                                                                 ref line_centre_y1);
                if (second_best_fit_line != null)
                {
                    // find a couple of points on the second best fit line
                    float sample_x2 = 100;
                    float sample_y2 = second_best_fit_line.RegVal(sample_x2);

                    //float hyp2 = (float)Math.Sqrt((sample_x2 * sample_x2) + (sample_y2 * sample_y2));
                    //float orient2 = (float)Math.Asin(sample_x2 / hyp2);
                    //if (sample_y2 < 0) orient2 = (float)(Math.PI * 2) - orient2;


                    // get the shear angle
                    shear_angle_radians = getShearAngle(
                        line_centre_x0, line_centre_y0,
                        line_centre_x0 + sample_x, line_centre_y0 + sample_y,
                        line_centre_x1, line_centre_y1,
                        line_centre_x1 + sample_x2, line_centre_y1 + sample_y2,
                        ref shear_angle_point);

                    // remove spots which are unlikely to be useful
                    removeSpots(spots, shear_angle_point, spot_culling_threshold);
                }

                // pixels per index defines the number of pixels which will be
                // represented by every index of the grid spacing array
                // This value should be proportional to the estimated spot radius
                // as previously derrived from a frequency analysis of the binary image
                float pixels_per_index = (spot_radius * grid_fitting_pixels_per_index);
                if (pixels_per_index < 0.1f) pixels_per_index = 0.1f;

                // create an array to store interceptions with the dominant axis
                grid_spacing_horizontal = new float[(int)(width * 2 / pixels_per_index) + 1];
                grid_spacing_vertical = new float[(int)(width * 2 / pixels_per_index) + 1];

                // find interception points between lines and the dominant axis
                int x0, y0, x1, y1;
                float dxx, dyy;            // vector in the dominant orientation
                float dxx2, dyy2;          // vector perpendicular to the dominant orientation
                float line_length = 1000;  // some arbitrary length - really all that we're interested in is the orientation
                float[] grid_spacing = null;
                for (int axis = 0; axis < 2; axis++)
                {
                    if (axis == 0)
                    {
                        grid_spacing = grid_spacing_horizontal;
                        // vector in the dominant orientation
                        dxx = line_length * (float)Math.Sin(dominant_orientation);
                        dyy = line_length * (float)Math.Cos(dominant_orientation);
                        // vector perpendicular to the dominant orientation
                        dxx2 = line_length * (float)Math.Sin(secondary_orientation);
                        dyy2 = line_length * (float)Math.Cos(secondary_orientation);
                    }
                    else
                    {
                        grid_spacing = grid_spacing_vertical;
                        // vector in the dominant orientation
                        dxx = line_length * (float)Math.Sin(secondary_orientation);
                        dyy = line_length * (float)Math.Cos(secondary_orientation);
                        // vector perpendicular to the dominant orientation
                        dxx2 = line_length * (float)Math.Sin(dominant_orientation);
                        dyy2 = line_length * (float)Math.Cos(dominant_orientation);
                    }

                    // coordinates for a line along the axis                
                    x0 = (int)(centre_x + dxx);
                    y0 = (int)(centre_y + dyy);
                    x1 = (int)(centre_x - dxx);
                    y1 = (int)(centre_y - dyy);

                    float histogram_max = 0;
                    if (spots != null)
                    {
                        for (int i = 0; i < spots.Count; i++)
                        {
                            blob spot = (blob)spots[i];

                            float px = spot.interpolated_x;
                            float py = spot.interpolated_y;

                            // locate intersection
                            float ix = 0, iy = 0; // intersection coordinate
                            sluggish.utilities.geometry.intersection(x0, y0, x1, y1,
                                                                     px, py,
                                                                     px + dxx2, py + dyy2,
                                                                     ref ix, ref iy);

                            if (ix != 9999)
                            {
                                // measure the distance of the intersection point from
                                // the centre of the region
                                float dx = ix - centre_x;
                                float dy = iy - centre_y;
                                float dist = (float)Math.Sqrt((dx * dx) + (dy * dy));
                                if (dist < width)
                                {
                                    if (((axis == 0) && (dy < 0)) ||
                                        ((axis == 1) && (dx < 0)))
                                        dist = -dist;

                                    int index = (int)Math.Round((dist / pixels_per_index) + (grid_spacing.Length / 2.0f));
                                    if (index >= grid_spacing.Length)
                                        index = grid_spacing.Length - 1;

                                    grid_spacing[index]++;

                                    if (grid_spacing[index] > histogram_max)
                                        histogram_max = grid_spacing[index];
                                }
                            }
                        }
                    }

                    if (histogram_max > 0)
                    {
                        for (int j = 0; j < grid_spacing.Length; j++)
                            grid_spacing[j] /= histogram_max;
                    }
                }

                // locate maxima within the horizontal and vertical graphs            
                float min_grid_threshold = 0.1f;
                int equalisation_steps = 1;
                equaliseGridAxes(ref horizontal_maxima, ref vertical_maxima,
                                 grid_spacing_horizontal,
                                 grid_spacing_vertical,
                                 pixels_per_index, grid_padding,
                                 supression_radius_factor,
                                 equalisation_steps,
                                 min_grid_threshold);


                // alternate the maxima points
                horizontal_maxima = alternateMaxima(horizontal_maxima);
                vertical_maxima = alternateMaxima(vertical_maxima);
            }

            return (grid);
        }
Exemple #23
0
        /// <summary>
        /// does this polygon overlap with the other, within the given screen dimensions
        /// </summary>
        /// <param name="other">other polygon object</param>
        /// <param name="image_width">image width</param>
        /// <param name="image_height">image height</param>
        /// <returns></returns>
        public bool overlaps(polygon2D other, int image_width, int image_height)
        {
            int i;
            bool retval = false;

            i = 0;
            while ((i < x_points.Count) && (retval == false))
            {
                if (other.isInside((float)x_points[i] * 1000 / image_width, (float)y_points[i] * 1000 / image_height)) retval = true;
                i++;
            }

            i = 0;
            while ((i < other.x_points.Count) && (retval == false))
            {
                if (isInside((float)other.x_points[i] * image_width / 1000, (float)other.y_points[i] * image_height / 1000)) retval = true;
                i++;
            }
            return (retval);
        }
Exemple #24
0
        /// <summary>
        /// initialise the snake based upon a polygon shape
        /// </summary>
        /// <param name="binary_image"></param>
        /// <param name="BlackOnWhite"></param>
        /// <param name="initial_points"></param>
        /// <param name="max_itterations"></param>
        /// <param name="rnd"></param>
        public void Snake(bool[,] binary_image, bool BlackOnWhite,
                          polygon2D initial_points,
                          int max_itterations,
                          Random rnd)
        {
            if (initial_points.x_points.Count > 1)
            {
                // get the perimeter length of the initial shape
                float perimeter_length = initial_points.getPerimeterLength();

                // distribute points evenly along the perimeter
                int side_index = 0;
                float side_length_total = 0;
                for (int i = 0; i < no_of_points; i++)
                {
                    // position of this point along the perimeter
                    float perimeter_position = i * perimeter_length / no_of_points;

                    float total = side_length_total;
                    while (total < perimeter_position)
                    {
                        side_length_total = total;
                        total += initial_points.getSideLength(side_index);
                        if (total < perimeter_position) side_index++;
                    }

                    float side_length = initial_points.getSideLength(side_index);
                    if (side_length > 0)
                    {
                        float perimeter_diff = perimeter_position - side_length_total;
                        float fraction = perimeter_diff / side_length;
                        float tx = 0, ty = 0, bx = 0, by = 0;
                        initial_points.getSidePositions(side_index, ref tx, ref ty, ref bx, ref by);
                        float dx = bx - tx;
                        float dy = by - ty;
                        SnakePoint[i, SNAKE_X] = tx + (dx * fraction);
                        SnakePoint[i, SNAKE_Y] = ty + (dy * fraction);
                    }
                }

                Snake(binary_image, BlackOnWhite, max_itterations, rnd);
            }
        }