/// <summary> /// links line features together /// It is assumed that all lines under consideration are of a similar orientation /// </summary> /// <param name="lines">list of line features to be joined</param> /// <param name="join_radius">the start or end points of the lines must be within this radius to be joined</param> public static ArrayList joinLines(ArrayList lines, float join_radius) { for (int i = 0; i < lines.Count-1; i++) { linefeature line1 = (linefeature)lines[i]; float min_start_start_separation = 9999; float min_start_end_separation = 9999; float min_end_start_separation = 9999; float min_end_end_separation = 9999; for (int j= i + 1; j < lines.Count; j++) { linefeature line2 = (linefeature)lines[j]; // start to start float dx = line2.x0 - line1.x0; if (dx < 0) dx = -dx; if (dx < join_radius) { float dy = line2.y0 - line1.y0; if (dy < 0) dy = -dy; if (dy < join_radius) { float separation = dx + dy; if (separation < min_start_start_separation) { min_start_start_separation = separation; line1.join_start = line2; line2.join_start = line1; } } } // start to end dx = line2.x1 - line1.x0; if (dx < 0) dx = -dx; if (dx < join_radius) { float dy = line2.y1 - line1.y0; if (dy < 0) dy = -dy; if (dy < join_radius) { float separation = dx + dy; if (separation < min_start_end_separation) { min_start_end_separation = separation; line1.join_start = line2; line2.join_end = line1; } } } // end to start dx = line2.x0 - line1.x1; if (dx < 0) dx = -dx; if (dx < join_radius) { float dy = line2.y0 - line1.y1; if (dy < 0) dy = -dy; if (dy < join_radius) { float separation = dx + dy; if (separation < min_end_start_separation) { min_end_start_separation = separation; line1.join_end = line2; line2.join_start = line1; } } } // end to end dx = line2.x1 - line1.x1; if (dx < 0) dx = -dx; if (dx < join_radius) { float dy = line2.y0 - line1.y1; if (dy < 0) dy = -dy; if (dy < join_radius) { float separation = dx + dy; if (separation < min_end_end_separation) { min_end_end_separation = separation; line1.join_end = line2; line2.join_end = line1; } } } } } ArrayList joined_lines = new ArrayList(); int max_joins = 10; for (int i = 0; i < lines.Count; i++) { linefeature line1 = (linefeature)lines[i]; if ((line1.join_start == null) && (line1.join_end == null)) { linefeature new_line = new linefeature(line1.x0, line1.y0, line1.x1, line1.y1); joined_lines.Add(new_line); } // note that we limit the number of itterations // to avoid getting trapped in circular joins linefeature current_line = line1; int l = 0; if (line1.join_start == null) { while ((l < max_joins) && (current_line.join_end != null)) { current_line = current_line.join_end; l++; } if (current_line != line1) { // make a new line which combines these linefeature new_line = new linefeature(line1.x0, line1.y0, current_line.x1, current_line.y1); joined_lines.Add(new_line); } } current_line = line1; l = 0; if (line1.join_end == null) { while ((l < max_joins) && (current_line.join_start != null)) { current_line = current_line.join_start; l++; } if (current_line != line1) { // make a new line which combines these linefeature new_line = new linefeature(current_line.x0, current_line.y0, line1.x1, line1.y1); joined_lines.Add(new_line); } } } return(joined_lines); }
/// <summary> /// trace along vertical edges /// </summary> /// <param name="vertical_edges">a list of vertical edge features</param> /// <param name="image_width">width of the image</param> /// <param name="min_length">the minimum length of line features to be extracted</param> /// <param name="search_depth">depth of search used to join edges</param> /// <returns>a list of line features</returns> public static ArrayList traceVerticalLines(ArrayList[] vertical_edges, int image_width, int min_length, int search_depth) { ArrayList lines = new ArrayList(); // arrays to store edge positions bool[] previous_edges4 = new bool[image_width]; bool[] previous_edges3 = new bool[image_width]; bool[] previous_edges2 = new bool[image_width]; bool[] previous_edges = new bool[image_width]; bool[] current_edges = new bool[image_width]; ArrayList[] current_lines = new ArrayList[image_width]; for (int y = 0; y < vertical_edges.Length; y++) { // clear the array of current edge positions for (int x = 0; x < image_width; x++) current_edges[x] = false; ArrayList edges = vertical_edges[y]; for (int i = 0; i < edges.Count; i++) { int x = (int)edges[i]; int prev_x = -1; if ((x > -1) && (x < image_width)) { if ((previous_edges[x]) || (previous_edges2[x]) || (previous_edges3[x]) || (previous_edges4[x])) prev_x = x; else { if (x > 0) if (previous_edges[x-1]) prev_x = x-1; if (x < image_width-1) if (previous_edges[x+1]) prev_x = x+1; if (search_depth > 1) { if (prev_x == -1) { if (x > 1) if (previous_edges[x - 2]) prev_x = x - 2; if (x < image_width - 2) if (previous_edges[x + 2]) prev_x = x + 2; } if (prev_x == -1) { if (x > 0) if (previous_edges2[x - 1]) prev_x = x - 1; if (x < image_width - 1) if (previous_edges2[x + 1]) prev_x = x + 1; } if (prev_x == -1) { if (x > 1) if (previous_edges2[x - 2]) prev_x = x - 2; if (x < image_width - 2) if (previous_edges2[x + 2]) prev_x = x + 2; } if (search_depth > 2) { if (prev_x == -1) { if (x > 0) if (previous_edges3[x - 1]) prev_x = x - 1; if (x < image_width - 1) if (previous_edges3[x + 1]) prev_x = x + 1; } if (prev_x == -1) { if (x > 1) if (previous_edges3[x - 2]) prev_x = x - 2; if (x < image_width - 2) if (previous_edges3[x + 2]) prev_x = x + 2; } if (search_depth > 3) { if (prev_x == -1) { if (x > 0) if (previous_edges4[x - 1]) prev_x = x - 1; if (x < image_width - 1) if (previous_edges4[x + 1]) prev_x = x + 1; } if (prev_x == -1) { if (x > 1) if (previous_edges4[x - 2]) prev_x = x - 2; if (x < image_width - 2) if (previous_edges4[x + 2]) prev_x = x + 2; } if (prev_x == -1) { if (x > 2) if (previous_edges4[x - 3]) prev_x = x - 3; if (x < image_width - 3) if (previous_edges4[x + 3]) prev_x = x + 3; } if (prev_x == -1) { if (x > 3) if (previous_edges4[x - 4]) prev_x = x - 4; if (x < image_width - 4) if (previous_edges4[x + 4]) prev_x = x + 4; } } } } } if (prev_x > -1) { if (current_lines[prev_x] == null) current_lines[prev_x] = new ArrayList(); current_lines[prev_x].Add(x); current_lines[prev_x].Add(y); if (prev_x != x) { current_lines[x] = current_lines[prev_x]; current_lines[prev_x] = null; } } current_edges[x] = true; } } // which lines are broken? for (int x = 1; x < image_width-1; x++) { ArrayList line = current_lines[x]; if ((line != null) && ((!current_edges[x]) || (y == vertical_edges.Length-1))) { int line_length = line.Count/2; if (line_length > min_length) { // calc centre of the line float av_start_x = 0; float av_start_y = 0; float av_end_x = 0; float av_end_y = 0; float av_x = 0; float av_y = 0; int hits_start = 0; int hits_end = 0; for (int j = 0; j < line.Count; j += 2) { int xx = (int)line[j]; int yy = (int)line[j + 1]; av_x += xx; av_y += yy; if (j < line_length) { av_start_x += xx; av_start_y += yy; hits_start++; } else { av_end_x += xx; av_end_y += yy; hits_end++; } } av_x /= line_length; av_y /= line_length; av_start_x /= hits_start; av_start_y /= hits_start; av_end_x /= hits_end; av_end_y /= hits_end; float dx = av_start_x - av_x; float dy = av_start_y - av_y; av_start_x = av_x + (dx*2); av_start_y = av_y + (dy*2); dx = av_end_x - av_x; dy = av_end_y - av_y; av_end_x = av_x + (dx*2); av_end_y = av_y + (dy*2); linefeature new_line = new linefeature(av_start_x, av_start_y, av_end_x, av_end_y); lines.Add(new_line); } current_lines[x] = null; } } // swap arrays bool[] temp = previous_edges4; previous_edges4 = previous_edges3; previous_edges3 = previous_edges2; previous_edges2 = previous_edges; previous_edges = current_edges; current_edges = temp; } return(lines); }