Example #1
0
        /// <summary>
        /// returns the length of the longest path from this blob feature
        /// </summary>
        /// <param name="mark_path">mark the longest path as being selected</param>
        /// <param name="best_end_point">blob at the longest distance</param>
        /// <returns></returns>
        public int getLongestPath(bool mark_path, ref blob end_point)
        {
            int   longest            = 0;
            float best_ang           = 0;
            float tollerance_degrees = 5;

            for (int i = 0; i < neighbours.Count; i++)
            {
                float ang            = (float)angle[i];
                blob  curr_end_point = null;
                int   length         = getDirectionalLength(ang, false, true, 0, 1000, tollerance_degrees, ref curr_end_point);

                if (length > longest)
                {
                    longest   = length;
                    best_ang  = ang;
                    end_point = curr_end_point;
                }
            }
            if ((longest > 0) && (mark_path))
            {
                blob curr_end_point = null;
                getDirectionalLength(best_ang, true, true, 0, 1000, tollerance_degrees, ref curr_end_point);
            }
            return(longest);
        }
Example #2
0
        /// <summary>
        /// returns the distance from this blob to another
        /// </summary>
        /// <param name="other">the other blob object</param>
        /// <returns>distance to the other blob</returns>
        public float getSeparation(blob other)
        {
            float dx   = other.interpolated_x - interpolated_x;
            float dy   = other.interpolated_y - interpolated_y;
            float dist = (float)Math.Sqrt((dx * dx) + (dy * dy));

            return(dist);
        }
Example #3
0
 /// <summary>
 /// returns a copy of this blob
 /// </summary>
 public blob Copy()
 {
     blob new_blob = new blob(x, y);
     new_blob.interpolated_x = interpolated_x;
     new_blob.interpolated_y = interpolated_y;
     new_blob.average_radius = average_radius;
     new_blob.ovality = ovality;
     new_blob.average_intensity = average_intensity;
     return (new_blob);
 }
Example #4
0
        /// <summary>
        /// returns a copy of this blob
        /// </summary>
        public blob Copy()
        {
            blob new_blob = new blob(x, y);

            new_blob.interpolated_x    = interpolated_x;
            new_blob.interpolated_y    = interpolated_y;
            new_blob.average_radius    = average_radius;
            new_blob.ovality           = ovality;
            new_blob.average_intensity = average_intensity;
            return(new_blob);
        }
Example #5
0
        /// <summary>
        /// add a neighbour if it's in da hood
        /// </summary>
        /// <param name="neighbour">a possibly neighbouring blob</param>
        /// <param name="neighbourhood_radius">the neighbourhood event horizon</param>
        public bool AddNeighbour(blob neighbour, float neighbourhood_radius)
        {
            float dx   = neighbour.interpolated_x - interpolated_x;
            float dy   = neighbour.interpolated_y - interpolated_y;
            float dist = (float)Math.Sqrt((dx * dx) + (dy * dy));

            if (dist < neighbourhood_radius)
            {
                AddNeighbour(neighbour);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #6
0
        /// <summary>
        /// everybody needs good neighbours...
        /// </summary>
        /// <param name="neighbour">a neighbouring blob</param>
        public void AddNeighbour(blob neighbour)
        {
            // update the neighbours list
            neighbours.Add(neighbour);

            // calculate the separation
            float dist = getSeparation(neighbour);

            separation.Add(dist);

            // calculate the angle to this neighbour
            float ang = 0;

            if (dist > 0.1f)
            {
                float dx = neighbour.interpolated_x - interpolated_x;
                float dy = neighbour.interpolated_y - interpolated_y;
                ang = (float)Math.Asin(dx / dist);
                if (dy < 0)
                {
                    ang = (float)(Math.PI * 2) - ang;
                }
                if (ang < 0)
                {
                    ang += (float)(Math.PI);
                }
                if (ang == float.NaN)
                {
                    ang = 0;
                }
            }
            angle.Add(ang);

            // populate the direction lookup table
            int ang_index = (int)Math.Round((ang * 180 / Math.PI) / direction_increment_degrees);

            if (ang_index >= neighbourDirections.Length)
            {
                ang_index = neighbourDirections.Length - 1;
            }
            if (neighbourDirections[ang_index] == null)
            {
                neighbourDirections[ang_index] = new ArrayList();
            }
            neighbourDirections[ang_index].Add(neighbours.Count - 1);
        }
Example #7
0
        /// <summary>
        /// add a neighbour if it's in da hood
        /// </summary>
        /// <param name="neighbour">a possibly neighbouring blob</param>
        /// <param name="neighbourhood_radius">the neighbourhood event horizon</param>
        public bool AddNeighbour(blob neighbour, float neighbourhood_radius)
        {
            float dx = neighbour.interpolated_x - interpolated_x;
            float dy = neighbour.interpolated_y - interpolated_y;
            float dist = (float)Math.Sqrt((dx * dx) + (dy * dy));

            if (dist < neighbourhood_radius)
            {
                AddNeighbour(neighbour);
                return (true);
            }
            else return (false);
        }
Example #8
0
 /// <summary>
 /// returns the distance from this blob to another
 /// </summary>
 /// <param name="other">the other blob object</param>
 /// <returns>distance to the other blob</returns>
 public float getSeparation(blob other)
 {
     float dx = other.interpolated_x - interpolated_x;
     float dy = other.interpolated_y - interpolated_y;
     float dist = (float)Math.Sqrt((dx * dx) + (dy * dy));
     return (dist);
 }
Example #9
0
        /// <summary>
        /// returns the length of the longest path from this blob feature
        /// </summary>
        /// <param name="mark_path">mark the longest path as being selected</param>
        /// <param name="best_end_point">blob at the longest distance</param>
        /// <returns></returns>
        public int getLongestPath(bool mark_path, ref blob end_point)
        {
            int longest = 0;
            float best_ang = 0;
            float tollerance_degrees = 5;

            for (int i = 0; i < neighbours.Count; i++)
            {
                float ang = (float)angle[i];
                blob curr_end_point = null;
                int length = getDirectionalLength(ang, false, true,0,1000, tollerance_degrees, ref curr_end_point);

                if (length > longest)
                {
                    longest = length;
                    best_ang = ang;
                    end_point = curr_end_point;
                }
            }
            if ((longest > 0) && (mark_path))
            {
                blob curr_end_point = null;
                getDirectionalLength(best_ang, true, true,0,1000, tollerance_degrees, ref curr_end_point);
            }
            return (longest);
        }
Example #10
0
        public int getDirectionalLength(float direction_radians, 
            bool mark_path,
            bool ignore_selected,
            int depth, int max_depth,
            float tollerance_degrees,
            ref blob end_point)
        {
            int length = 0;

            // mark the path if necessary
            if (mark_path) selected = true;

            if (depth < max_depth)
            {
                // get the index of the lookup table for this direction
                int ang_index = (int)Math.Round((direction_radians * 180 / Math.PI) / direction_increment_degrees);
                if (ang_index >= neighbourDirections.Length)
                    ang_index -= neighbourDirections.Length;

                // search for neighbours in this direction
                float max_ang_diff = tollerance_degrees * (float)Math.PI / 180.0f;
                //float closest_ang = 0;
                blob winner = null;
                for (int j = -1; j <= 1; j++)
                {
                    if ((ang_index + j > -1) &&
                        (ang_index + j < neighbourDirections.Length))
                    {
                        // are there any neighbours in this direction?
                        if (neighbourDirections[ang_index + j] != null)
                        {
                            // search through all neighbours to find the one which
                            // has the most similar direction
                            for (int i = 0; i < neighbourDirections[ang_index + j].Count; i++)
                            {
                                int neighbour_index = (int)neighbourDirections[ang_index + j][i];
                                if ((!ignore_selected) ||
                                   ((ignore_selected) && (!((blob)neighbours[neighbour_index]).selected)))
                                {
                                    float neighbour_ang = (float)angle[neighbour_index];
                                    float ang_diff = Math.Abs(neighbour_ang - direction_radians);
                                    if (ang_diff < max_ang_diff)
                                    {
                                        // this is the most similar direction yet found
                                        //closest_ang = neighbour_ang;
                                        max_ang_diff = ang_diff;
                                        winner = (blob)neighbours[neighbour_index];
                                    }
                                }
                            }
                        }
                    }
                }
                if ((winner != null) && (winner != this))
                {
                    // alter the search direction slighly
                    // note: this might not be needed
                    //direction_radians = (direction_radians * 0.8f) + (closest_ang * 0.2f);

                    // keep note of the end point
                    end_point = winner;

                    // update the length, then carry on searching
                    length = 1 + winner.getDirectionalLength(direction_radians, mark_path, ignore_selected, depth + 1, max_depth, tollerance_degrees, ref end_point);
                }
            }

            return (length);
        }
Example #11
0
        /// <summary>
        /// everybody needs good neighbours...
        /// </summary>
        /// <param name="neighbour">a neighbouring blob</param>
        public void AddNeighbour(blob neighbour)
        {
            // update the neighbours list
            neighbours.Add(neighbour);

            // calculate the separation
            float dist = getSeparation(neighbour);
            separation.Add(dist);

            // calculate the angle to this neighbour
            float ang = 0;
            if (dist > 0.1f)
            {
                float dx = neighbour.interpolated_x - interpolated_x;
                float dy = neighbour.interpolated_y - interpolated_y;
                ang = (float)Math.Asin(dx / dist);
                if (dy < 0) ang = (float)(Math.PI * 2) - ang;
                if (ang < 0) ang += (float)(Math.PI);
                if (ang == float.NaN) ang = 0;
            }
            angle.Add(ang);

            // populate the direction lookup table
            int ang_index = (int)Math.Round((ang * 180 / Math.PI) / direction_increment_degrees);
            if (ang_index >= neighbourDirections.Length)
                ang_index = neighbourDirections.Length - 1;
            if (neighbourDirections[ang_index] == null)
                neighbourDirections[ang_index] = new ArrayList();
            neighbourDirections[ang_index].Add(neighbours.Count-1);
        }
Example #12
0
        /// <summary>
        /// detect spots within the region
        /// </summary>
        /// <param name="black_on_white">whether this image contains darker features on a lighter background</param>
        /// <param name="spot_detection_threshold">threshold used to remove low magnitude spot responses</param>
        /// <param name="max_radius_variance">maximum allowable variation in spot radius</param>
        /// <param name="minimum_spot_diameter_percent">minimum spot diameter as a percentage of the region height, which allows the system to ignore noise</param>
        public void detectSpots(bool black_on_white,
                                float spot_detection_threshold,
                                float max_radius_variance,
                                float minimum_spot_diameter_percent)
        {
            // create a map of spottyness
            spot_map = new float[width, height];

            // this map will contain the positions of spot centres
            // after non-maximal supression
            float[,] spot_centres_map = new float[width, height];

            float maximal_response = 0;

            // estimate the spot radius if necessary
            if (spot_radius == 0)
                spot_radius = getSpotAverageRadius(black_on_white, minimum_spot_diameter_percent);

            // spot radius as an integer
            //int spot_radius_rounded = (int)Math.Round(spot_radius);
            int spot_radius_rounded = (int)spot_radius;

            // make an integral image from the binary image to speed things up
            int[,] integral_image = binaryIntegralImage(black_on_white);

            // apply the mask to the region of interest
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    int txx = x - spot_radius_rounded;
                    int tyy = y - spot_radius_rounded;
                    int bxx = x + spot_radius_rounded;
                    int byy = y + spot_radius_rounded;

                    if (txx < 0) txx = 0;
                    if (tyy < 0) tyy = 0;
                    if (bxx >= width) bxx = width - 1;
                    if (byy >= height) byy = height - 1;

                    // get the magnitude of response at this point
                    int spot_response_magnitude = binaryGetIntegral(integral_image, txx, tyy, bxx, byy);

                    // update the map using squared magnitude
                    int squared_magnitude = spot_response_magnitude * spot_response_magnitude;
                    spot_map[x, y] = squared_magnitude;

                    // record the maximal response
                    if (squared_magnitude > maximal_response)
                        maximal_response = squared_magnitude;
                }
            }

            if (maximal_response > 0)
            {
                // errode the contours of the map (like mountains becoming weathered)
                // this helps to eliminate plateau regions where the 
                // response is locally maximum

                // erode horizontally
                for (int y = 1; y < height; y++)
                {
                    float prev_spot_value = 0;
                    for (int x = 1; x < width; x++)
                    {
                        float spot_value = spot_map[x, y];
                        float new_spot_value = prev_spot_value + ((spot_value - prev_spot_value) / 2);
                        spot_map[x, y] = new_spot_value;
                        prev_spot_value = new_spot_value;
                    }
                }
                // erode vertically
                maximal_response = 0;
                for (int x = 1; x < width; x++)
                {
                    float prev_spot_value = 0;
                    for (int y = 1; y < height; y++)
                    {
                        float spot_value = spot_map[x, y];
                        float new_spot_value = prev_spot_value + ((spot_value - prev_spot_value) / 2);
                        spot_map[x, y] = new_spot_value;
                        prev_spot_value = new_spot_value;

                        // find the maximal response, which will allow
                        // subsequent normalisation
                        if (new_spot_value > maximal_response)
                            maximal_response = new_spot_value;
                    }
                }

                // normalise spot responses, and apply threshold to spot centres map
                for (int x = 0; x < width; x++)
                    for (int y = 0; y < height; y++)
                    {
                        float spot_value = spot_map[x, y] / maximal_response;
                        spot_centres_map[x, y] = spot_value;
                        spot_map[x, y] = spot_value;
                        if (spot_value < spot_detection_threshold)
                            spot_centres_map[x, y] = 0;
                    }

                // perform non-maximal supression
                int supression_radius = (int)(spot_radius * 19 / 10);
                for (int x = 0; x < width; x++)
                    for (int y = 0; y < height; y++)
                    {
                        if (spot_centres_map[x, y] > 0)
                        {
                            bool killed = false;

                            int xx = x - supression_radius;
                            while ((xx <= x + supression_radius) && (!killed))
                            {
                                if ((xx > -1) && (xx < width))
                                {
                                    int yy = y - supression_radius;
                                    while ((yy <= y + supression_radius) && (!killed))
                                    {
                                        if ((yy > -1) && (yy < height))
                                        {
                                            if (!((xx == x) && (yy == y)))
                                            {
                                                if (spot_centres_map[x, y] >= spot_centres_map[xx, yy])
                                                    spot_centres_map[xx, yy] = 0;
                                                else
                                                {
                                                    spot_centres_map[x, y] = 0;
                                                    killed = true;
                                                }
                                            }
                                        }
                                        yy++;
                                    }
                                }
                                xx++;
                            }
                        }
                    }

                // store the spot centres in a list
                spots = new ArrayList();
                for (int x = 0; x < width; x++)
                    for (int y = 0; y < height; y++)
                        if (spot_centres_map[x, y] > 0)
                        {
                            blob new_spot = new blob(x, y);
                            spots.Add(new_spot);
                        }

                // sub-pixel interpolate spot positions
                for (int i = 0; i < spots.Count; i++)
                {
                    blob spot = (blob)spots[i];
                    float interpolated_x = 0;
                    float interpolated_y = 0;
                    float interpolated_total = 0;
                    for (int x = (int)spot.x - 1; x <= (int)spot.x + 1; x++)
                    {
                        if ((x > -1) && (x < width))
                        {
                            for (int y = (int)spot.y - 1; y <= (int)spot.y + 1; y++)
                            {
                                if ((y > -1) && (y < height))
                                {
                                    float map_value = spot_map[x, y];
                                    map_value *= map_value;
                                    interpolated_total += map_value;
                                    interpolated_x += (map_value * x);
                                    interpolated_y += (map_value * y);
                                }
                            }
                        }
                    }
                    if (interpolated_total > 0)
                    {
                        interpolated_x /= interpolated_total;
                        interpolated_y /= interpolated_total;
                        spot.interpolated_x = interpolated_x;
                        spot.interpolated_y = interpolated_y;
                    }
                }

                // detect radii
                detectSpotRadii(max_radius_variance);
            }
        }
Example #13
0
 /// <summary>
 /// returns a list of spots arranged in a line between the two given spots
 /// </summary>
 /// <param name="spot1">the first spot</param>
 /// <param name="spot2">the second spot</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>
 /// <returns></returns>
 private ArrayList SpotsConnected(blob spot1, blob spot2, float max_distance, ref float average_separation)
 {
     return (SpotsIntersectWithLine(spot1.interpolated_x, spot1.interpolated_y, spot2.interpolated_x, spot2.interpolated_y, max_distance, ref average_separation));
 }
Example #14
0
        public int getDirectionalLength(float direction_radians,
                                        bool mark_path,
                                        bool ignore_selected,
                                        int depth, int max_depth,
                                        float tollerance_degrees,
                                        ref blob end_point)
        {
            int length = 0;

            // mark the path if necessary
            if (mark_path)
            {
                selected = true;
            }

            if (depth < max_depth)
            {
                // get the index of the lookup table for this direction
                int ang_index = (int)Math.Round((direction_radians * 180 / Math.PI) / direction_increment_degrees);
                if (ang_index >= neighbourDirections.Length)
                {
                    ang_index -= neighbourDirections.Length;
                }

                // search for neighbours in this direction
                float max_ang_diff = tollerance_degrees * (float)Math.PI / 180.0f;
                //float closest_ang = 0;
                blob winner = null;
                for (int j = -1; j <= 1; j++)
                {
                    if ((ang_index + j > -1) &&
                        (ang_index + j < neighbourDirections.Length))
                    {
                        // are there any neighbours in this direction?
                        if (neighbourDirections[ang_index + j] != null)
                        {
                            // search through all neighbours to find the one which
                            // has the most similar direction
                            for (int i = 0; i < neighbourDirections[ang_index + j].Count; i++)
                            {
                                int neighbour_index = (int)neighbourDirections[ang_index + j][i];
                                if ((!ignore_selected) ||
                                    ((ignore_selected) && (!((blob)neighbours[neighbour_index]).selected)))
                                {
                                    float neighbour_ang = (float)angle[neighbour_index];
                                    float ang_diff      = Math.Abs(neighbour_ang - direction_radians);
                                    if (ang_diff < max_ang_diff)
                                    {
                                        // this is the most similar direction yet found
                                        //closest_ang = neighbour_ang;
                                        max_ang_diff = ang_diff;
                                        winner       = (blob)neighbours[neighbour_index];
                                    }
                                }
                            }
                        }
                    }
                }
                if ((winner != null) && (winner != this))
                {
                    // alter the search direction slighly
                    // note: this might not be needed
                    //direction_radians = (direction_radians * 0.8f) + (closest_ang * 0.2f);

                    // keep note of the end point
                    end_point = winner;

                    // update the length, then carry on searching
                    length = 1 + winner.getDirectionalLength(direction_radians, mark_path, ignore_selected, depth + 1, max_depth, tollerance_degrees, ref end_point);
                }
            }

            return(length);
        }