/// <summary> /// returns an ideal grid with perfectly regular spacing /// </summary> /// <param name="grid"></param> /// <param name="image_width"></param> /// <param name="image_height"></param> /// <returns> /// </returns> private static grid2D GetIdealGrid(CalibrationDot[,] grid, int image_width, int image_height) { grid2D ideal_grid = null; float ideal_spacing = 0; double centre_x = image_width / 2; double centre_y = image_height / 2; double min_dist = double.MaxValue; int grid_cx=0, grid_cy=0; for (int x = 0; x < grid.GetLength(0); x++) { for (int y = 0; y < grid.GetLength(1); y++) { if (grid[x, y] != null) { double dx = grid[x, y].x - centre_x; double dy = grid[x, y].y - centre_y; double dist = dx*dx + dy*dy; if (dist < min_dist) { min_dist = dist; grid_cx = x; grid_cy = y; } } } } if (grid_cx > 0) { int[] orientation_histogram = new int[361]; List<double>[] orientations = new List<double>[361]; double average_dist = 0; int hits = 0; int local_search = 2; for (int x = grid_cx - local_search; x <= grid_cx + local_search; x++) { if ((x >= 0) && (x < grid.GetLength(0)-1)) { for (int y = grid_cy - local_search; y <= grid_cy + local_search; y++) { if ((y >= 1) && (y < grid.GetLength(1)-1)) { if (grid[x, y] != null) { for (int i = 0; i < grid[x, y].Links.Count; i++) { CalibrationLink link = (CalibrationLink)grid[x, y].Links[i]; CalibrationDot from_dot = (CalibrationDot)link.From; double dx = grid[x, y].x - from_dot.x; double dy = grid[x, y].y - from_dot.y; double dist = Math.Sqrt(dx*dx + dy*dy); if (dist > 0) { double orientation = Math.Asin(dx / dist); if (orientation < 0) orientation += Math.PI; if (dy < 0) orientation = (Math.PI * 2) - orientation; orientation = orientation / Math.PI * 180; int bucket = (int)orientation; orientation_histogram[bucket]++; if (orientations[bucket] == null) orientations[bucket] = new List<double>(); orientations[bucket].Add(orientation); average_dist += Math.Sqrt(dx*dx + dy*dy); hits++; } } } } } } } if (hits > 0) average_dist = average_dist / hits; ideal_spacing = (float)average_dist; int max_orientation_response = 0; int best_ang = 0; for (int ang = 0; ang < 90; ang++) { int response = orientation_histogram[ang] + orientation_histogram[ang + 90] + orientation_histogram[ang + 180]; if (response > max_orientation_response) { max_orientation_response = response; best_ang = ang; } } double average_orientation = 0; hits = 0; for (int offset = 0; offset < 3; offset++) { if (orientations[best_ang + offset] != null) { for (int ang = 0; ang < orientations[best_ang + offset].Count; ang++) { average_orientation += orientations[best_ang + offset][ang] - (Math.PI*offset/2); hits++; } } } if (hits > 0) { average_orientation /= hits; float pattern_orientation = (float)average_orientation; float offset_x = (float)grid[grid_cx, grid_cy].x; float offset_y = (float)grid[grid_cx, grid_cy].y; float r = ideal_spacing * dots_across; polygon2D perimeter = new polygon2D(); perimeter.Add(-r + offset_x, -r + offset_y); perimeter.Add(r + offset_x, -r + offset_y); perimeter.Add(r + offset_x, r + offset_y); perimeter.Add(-r + offset_x, r + offset_y); perimeter.rotate((float)average_orientation / 180 * (float)Math.PI, offset_x, offset_y); ideal_grid = new grid2D(dots_across*2, dots_across*2, perimeter, 0, false); int grid_width = grid.GetLength(0); int grid_height = grid.GetLength(1); int idx = 0; int xx=0, yy=0; float ideal_x, ideal_y; for (int orient = 0; orient < 8; orient++) { for (int x = 0; x < grid_width; x++) { for (int y = 0; y < grid_height; y++) { if (grid[x, y] != null) { switch(orient) { case 0: { xx = (x - grid_cx) + dots_across; yy = (y - grid_cy) + dots_across; break; } case 1: { xx = (x - grid_cx) + dots_across; yy = (grid_cy - y) + dots_across; break; } case 2: { xx = (grid_cx - x) + dots_across; yy = (y - grid_cy) + dots_across; break; } case 3: { xx = (grid_cx - x) + dots_across; yy = (grid_cy - y) + dots_across; break; } case 4: { xx = (y - grid_cy) + dots_across; yy = (x - grid_cx) + dots_across; break; } case 5: { xx = (y - grid_cy) + dots_across; yy = (grid_cx - x) + dots_across; break; } case 6: { xx = (grid_cy - y) + dots_across; yy = (x - grid_cx) + dots_across; break; } case 7: { xx = (grid_cy - y) + dots_across; yy = (grid_cx - x) + dots_across; break; } } if ((xx >= 0) && (xx < ideal_grid.cell.Length) && (yy >= 0) && (yy < ideal_grid.cell[0].Length)) { ideal_x = ideal_grid.cell[xx][yy].perimeter.x_points[idx]; ideal_y = ideal_grid.cell[xx][yy].perimeter.y_points[idx]; if (orient == 0) { grid[x, y].rectified_x = ideal_x; grid[x, y].rectified_y = ideal_y; } else { double diff_x1 = grid[x, y].rectified_x - grid[x, y].x; double diff_y1 = grid[x, y].rectified_y - grid[x, y].y; double dist1 = diff_x1*diff_x1 + diff_y1*diff_y1; double diff_x2 = ideal_x - grid[x, y].x; double diff_y2 = ideal_y - grid[x, y].y; double dist2 = diff_x2*diff_x2 + diff_y2*diff_y2; if (dist2 < dist1) { grid[x, y].rectified_x = ideal_x; grid[x, y].rectified_y = ideal_y; } } } } } } } } } return(ideal_grid); }