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]); } }
/// <summary> /// simple function used to test grid creation /// </summary> /// <param name="filename">filename of the test image to be created</param> public static void Test(string filename) { int image_width = 640; int image_height = 480; int dimension_x = 10; int dimension_y = 10; Bitmap bmp = new Bitmap(image_width, image_height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); byte[] img = new byte[image_width * image_height * 3]; polygon2D test_poly; grid2D grid; test_poly = new polygon2D(); test_poly.Add(image_width * 15 / 100, image_height * 20 / 100); test_poly.Add(image_width * 40 / 100, image_height * 20 / 100); test_poly.Add(image_width * 40 / 100, image_height * 40 / 100); test_poly.Add(image_width * 15 / 100, image_height * 40 / 100); grid = new grid2D(dimension_x, dimension_y, test_poly, 0, false); grid.ShowLines(img, image_width, image_height, 0, 255, 0, 0); int half_width = image_width / 2; test_poly = new polygon2D(); test_poly.Add(half_width + (image_width * 20 / 100), image_height * 20 / 100); test_poly.Add(half_width + (image_width * 35 / 100), image_height * 20 / 100); test_poly.Add(half_width + (image_width * 40 / 100), image_height * 40 / 100); test_poly.Add(half_width + (image_width * 15 / 100), image_height * 40 / 100); grid = new grid2D(dimension_x, dimension_y, test_poly, 0, false); grid.ShowLines(img, image_width, image_height, 0, 255, 0, 0); int half_height = image_height / 2; test_poly = new polygon2D(); test_poly.Add(image_width * 15 / 100, half_height + (image_height * 24 / 100)); test_poly.Add(image_width * 40 / 100, half_height + (image_height * 20 / 100)); test_poly.Add(image_width * 40 / 100, half_height + (image_height * 40 / 100)); test_poly.Add(image_width * 15 / 100, half_height + (image_height * 36 / 100)); grid = new grid2D(dimension_x, dimension_y, test_poly, 0, false); grid.ShowLines(img, image_width, image_height, 0, 255, 0, 0); test_poly = new polygon2D(); test_poly.Add(half_width + (image_width * 20 / 100), half_height + (image_height * 24 / 100)); test_poly.Add(half_width + (image_width * 35 / 100), half_height + (image_height * 20 / 100)); test_poly.Add(half_width + (image_width * 40 / 100), half_height + (image_height * 40 / 100)); test_poly.Add(half_width + (image_width * 15 / 100), half_height + (image_height * 36 / 100)); grid = new grid2D(dimension_x, dimension_y, test_poly, 0, false); grid.ShowLines(img, image_width, image_height, 0, 255, 0, 0); BitmapArrayConversions.updatebitmap_unsafe(img, bmp); bmp.Save(filename); }
/// <summary> /// finds the interception points between grid lines /// </summary> private void poltLineIntercepts() { if (line != null) { // create an array to store the line intercepts int intercepts_x = line[0].Count / 4; int intercepts_y = line[1].Count / 4; line_intercepts = new float[intercepts_x, intercepts_y, 2]; for (int i = 0; i < line[0].Count; i += 4) { // get the first line coordinates ArrayList lines0 = line[0]; float x0 = (float)lines0[i]; float y0 = (float)lines0[i + 1]; float x1 = (float)lines0[i + 2]; float y1 = (float)lines0[i + 3]; for (int j = 0; j < line[1].Count; j += 4) { // get the second line coordinates ArrayList lines1 = line[1]; float x2 = (float)lines1[j]; float y2 = (float)lines1[j + 1]; float x3 = (float)lines1[j + 2]; float y3 = (float)lines1[j + 3]; // find the interception between the two lines float ix = 0, iy = 0; geometry.intersection(x0, y0, x1, y1, x2, y2, x3, y3, ref ix, ref iy); // store the intercept position line_intercepts[i / 4, j / 4, 0] = ix; line_intercepts[i / 4, j / 4, 1] = iy; } } // update the perimeter border_perimeter = new polygon2D(); float xx = line_intercepts[0, 0, 0]; float yy = line_intercepts[0, 0, 1]; border_perimeter.Add(xx, yy); xx = line_intercepts[intercepts_x - 1, 0, 0]; yy = line_intercepts[intercepts_x - 1, 0, 1]; border_perimeter.Add(xx, yy); xx = line_intercepts[intercepts_x - 1, intercepts_y - 1, 0]; yy = line_intercepts[intercepts_x - 1, intercepts_y - 1, 1]; border_perimeter.Add(xx, yy); xx = line_intercepts[0, intercepts_y - 1, 0]; yy = line_intercepts[0, intercepts_y - 1, 1]; border_perimeter.Add(xx, yy); } }
/// <summary> /// creates a circle shape /// </summary> /// <param name="centre_x"> /// centre x coordinate of the circle <see cref="System.Single"/> /// </param> /// <param name="centre_y"> /// centre y coordinate of the circle <see cref="System.Single"/> /// </param> /// <param name="radius"> /// radius of the circle <see cref="System.Single"/> /// </param> /// <param name="circumference_steps"> /// number of steps to use when drawing the circle <see cref="System.Int32"/> /// </param> /// <returns> /// polygon representing a circle <see cref="polygon2D"/> /// </returns> public static polygon2D CreateCircle(float centre_x, float centre_y, float radius, int circumference_steps) { polygon2D circle = new polygon2D(); for (int i = 0; i < circumference_steps; i++) { float angle = i * (float)Math.PI * 2 / circumference_steps; float x = centre_x + (radius * (float)Math.Sin(angle)); float y = centre_y + (radius * (float)Math.Cos(angle)); circle.Add(x, y); } return(circle); }
/// <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); } }
/// <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 = x_points[i]; float y = y_points[i]; new_poly.Add(x, y); } } return (new_poly); }
/// <summary> /// rescales the grid to a larger or smaller image /// </summary> /// <param name="original_image_width"></param> /// <param name="original_image_height"></param> /// <param name="new_image_width"></param> /// <param name="new_image_height"></param> /// <returns></returns> public grid2D Scale(int original_image_width, int original_image_height, int new_image_width, int new_image_height) { polygon2D new_perimeter = perimeter.Copy(); for (int i = 0; i < new_perimeter.x_points.Count; i++) { float x = (float)new_perimeter.x_points[i] * new_image_width / original_image_width; float y = (float)new_perimeter.y_points[i] * new_image_height / original_image_height; new_perimeter.x_points[i] = x; new_perimeter.y_points[i] = y; } grid2D new_grid = new grid2D(cell.Length, cell[0].Length); new_grid.init(cell.Length, cell[0].Length, new_perimeter, 0, false); return(new_grid); }
/// <summary> /// initialise the grid /// </summary> /// <param name="dimension_x"></param> /// <param name="dimension_y"></param> /// <param name="perimeter"></param> /// <param name="border_cells"></param> /// <param name="simple_orientation"></param> public void init(int dimension_x, int dimension_y, polygon2D perimeter, int border_cells, bool simple_orientation) { this.border_cells = border_cells; this.perimeter = perimeter; cell = new grid2Dcell[dimension_x][]; for (int x = 0; x < dimension_x; x++) { cell[x] = new grid2Dcell[dimension_y]; } line = new ArrayList[2]; float length3, length4; int index = 0; for (int i = 0; i < 2; i++) { line[i] = new ArrayList(); int idx1 = index + i; if (idx1 >= 4) { idx1 -= 4; } int idx2 = index + i + 1; if (idx2 >= 4) { idx2 -= 4; } float x0 = (float)perimeter.x_points[idx1]; float y0 = (float)perimeter.y_points[idx1]; float x1 = (float)perimeter.x_points[idx2]; float y1 = (float)perimeter.y_points[idx2]; int next_idx1 = idx1 + 1; if (next_idx1 >= 4) { next_idx1 -= 4; } length3 = perimeter.getSideLength(next_idx1); float w0 = Math.Abs(x1 - x0); float h0 = Math.Abs(y1 - y0); int idx3 = index + i + 2; if (idx3 >= 4) { idx3 -= 4; } int idx4 = index + i + 3; if (idx4 >= 4) { idx4 -= 4; } float x2 = (float)perimeter.x_points[idx3]; float y2 = (float)perimeter.y_points[idx3]; float x3 = (float)perimeter.x_points[idx4]; float y3 = (float)perimeter.y_points[idx4]; int next_idx3 = next_idx1 + 2; if (next_idx3 >= 4) { next_idx3 -= 4; } length4 = perimeter.getSideLength(next_idx3); float w1 = Math.Abs(x3 - x2); float h1 = Math.Abs(y3 - y2); int dimension = dimension_x; if (!simple_orientation) { if (i > 0) { dimension = dimension_y; } } else { if (h0 > w0) { dimension = dimension_y; } } // how much shorter is one line than the other on the opposite axis? float shortening = 0; //if (h0 > w0) { if (length3 > length4) { shortening = (length3 - length4) / length3; } else { shortening = (length4 - length3) / length4; } } for (int j = -border_cells; j <= dimension + border_cells; j++) { // locate the position along the first line float xx0, yy0; // position along the first line float fraction = j / (float)dimension; // modify for foreshortening //if ((h0 > w0) && (shortening > 0)) if (shortening > 0) { fraction = (fraction * (1.0f - shortening)) + ((float)Math.Sin(fraction * (float)Math.PI / 2) * shortening); if (length3 > length4) { fraction = 1.0f - fraction; } } if (w0 > h0) { float grad = (y1 - y0) / (x1 - x0); if (x1 > x0) { xx0 = x0 + (w0 * fraction); } else { xx0 = x0 - (w0 * fraction); } yy0 = y0 + ((xx0 - x0) * grad); } else { float grad = (x1 - x0) / (y1 - y0); if (y1 > y0) { yy0 = y0 + (h0 * fraction); } else { yy0 = y0 - (h0 * fraction); } xx0 = x0 + ((yy0 - y0) * grad); } // locate the position along the second line float xx1, yy1; // position along the second line if (w1 > h1) { float grad = (y2 - y3) / (x2 - x3); if (x2 > x3) { xx1 = x3 + (w1 * fraction); } else { xx1 = x3 - (w1 * fraction); } yy1 = y3 + ((xx1 - x3) * grad); } else { float grad = (x2 - x3) / (y2 - y3); if (y2 > y3) { yy1 = y3 + (h1 * fraction); } else { yy1 = y3 - (h1 * fraction); } xx1 = x3 + ((yy1 - y3) * grad); } // add the line to the list line[i].Add(xx0); line[i].Add(yy0); line[i].Add(xx1); line[i].Add(yy1); } } // find interceptions between lines poltLineIntercepts(); // create grid cells initialiseCells(); }
/// <summary> /// shows the detected centre square /// </summary> /// <param name="filename">raw image filename</param> /// <param name="square">square to be displayed</param> /// <param name="output_filename">filename to save as</param> private static void ShowSquare(string filename, polygon2D square, string output_filename) { Bitmap bmp = (Bitmap)Bitmap.FromFile(filename); byte[] img = new byte[bmp.Width * bmp.Height * 3]; BitmapArrayConversions.updatebitmap(bmp, img); square.show(img, bmp.Width, bmp.Height, 0, 255, 0, 0); Bitmap output_bmp = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); BitmapArrayConversions.updatebitmap_unsafe(img, output_bmp); if (output_filename.ToLower().EndsWith("jpg")) output_bmp.Save(output_filename, System.Drawing.Imaging.ImageFormat.Jpeg); if (output_filename.ToLower().EndsWith("bmp")) output_bmp.Save(output_filename, System.Drawing.Imaging.ImageFormat.Bmp); }
/// <summary> /// locates the centre position of a spot /// </summary> /// <param name="raw_image_mono">mono image data</param> /// <param name="raw_image_width">image width</param> /// <param name="raw_image_height">image height</param> /// <param name="search_region">region within which to search</param> /// <param name="black_on_white">whether this image contains dark markings on a lighter background</param> /// <param name="centre_x">returned x centre position</param> /// <param name="centre_y">returned y centre position</param> private static unsafe void LocateSpotCentre(byte* raw_image_mono, int raw_image_width, int raw_image_height, polygon2D search_region, bool black_on_white, ref float centre_x, ref float centre_y) { centre_x = 0; centre_y = 0; // get dimensions of the region to be searched int tx = (int)search_region.left(); //int ty = (int)search_region.top(); int bx = (int)search_region.right(); //int by = (int)search_region.bottom(); int r = (bx - tx) / 3; if (r < 1) r = 1; int search_r = (bx - tx) / 4; if (search_r < 1) search_r = 1; // centre of the search region float search_centre_x = 0; float search_centre_y = 0; search_region.GetSquareCentre(ref search_centre_x, ref search_centre_y); //search_region.getCentreOfGravity(ref search_centre_x, ref search_centre_y); int image_pixels = raw_image_width * raw_image_height; float max = 0; float v; for (float offset_y = search_centre_y - search_r; offset_y <= search_centre_y + search_r; offset_y += 0.5f) { for (float offset_x = search_centre_x - search_r; offset_x <= search_centre_x + search_r; offset_x += 0.5f) { float tot = 0; for (int yy = (int)(offset_y - r); yy <= (int)(offset_y + r); yy += 2) { int n0 = yy * raw_image_width; for (int xx = (int)(offset_x - r); xx <= (int)(offset_x + r); xx += 2) { int n1 = n0 + xx; if ((n1 > -1) && (n1 < image_pixels)) { if (black_on_white) v = 255 - raw_image_mono[n1]; else v = raw_image_mono[n1]; tot += v * v; } } } if (tot > max) { max = tot; centre_x = offset_x; centre_y = offset_y; } } } }
/// <summary> /// constructor /// </summary> /// <param name="dimension_x">number of cells across the grid</param> /// <param name="dimension_y">number of cells down the grid</param> /// <param name="perimeter">perimeter of the grid</param> /// <param name="border_cells">number of cells to use as a border around the grid</param> /// <param name="orientation_simple"></param> public grid2D(int dimension_x, int dimension_y, polygon2D perimeter, int border_cells, bool orientation_simple) { init(dimension_x, dimension_y, perimeter, border_cells, orientation_simple); }
/// <summary> /// detect a grid within the given image using the given perimeter polygon /// </summary> /// <param name="img">image data</param> /// <param name="img_width">width of the image</param> /// <param name="img_height">height of the image</param> /// <param name="bytes_per_pixel">number of bytes per pixel</param> /// <param name="perimeter">bounding perimeter within which the grid exists</param> /// <param name="spot_centres">previously detected spot centres</param> /// <param name="minimum_dimension_horizontal">minimum number of cells across</param> /// <param name="maximum_dimension_horizontal">maximum number of cells across</param> /// <param name="minimum_dimension_vertical">minimum number of cells down</param> /// <param name="maximum_dimension_vertical">maximum number of cells down</param> /// <param name="known_grid_spacing">known grid spacing (cell diameter) value in pixels</param> /// <param name="known_even_dimension">set to true if it is known that the number of cells in horizontal and vertical axes is even</param> /// <param name="border_cells">extra cells to add as a buffer zone around the grid</param> /// <param name="horizontal_scale_spacings">description used on the spacings diagram</param> /// <param name="vertical_scale_spacings">description used on the spacings diagram</param> /// <returns>2D grid</returns> public static grid2D DetectGrid(byte[] img, int img_width, int img_height, int bytes_per_pixel, polygon2D perimeter, ArrayList spot_centres, int minimum_dimension_horizontal, int maximum_dimension_horizontal, int minimum_dimension_vertical, int maximum_dimension_vertical, float known_grid_spacing, bool known_even_dimension, int border_cells, String horizontal_scale_spacings, String vertical_scale_spacings, ref float average_spacing_horizontal, ref float average_spacing_vertical, ref byte[] output_img, int output_img_type) { int tx = (int)perimeter.left(); int ty = (int)perimeter.top(); int bx = (int)perimeter.right(); int by = (int)perimeter.bottom(); // adjust spot centre positions so that they're relative to the perimeter // top left position if (spot_centres != null) { for (int i = 0; i < spot_centres.Count; i += 2) { spot_centres[i] = (float)spot_centres[i] - tx; spot_centres[i + 1] = (float)spot_centres[i + 1] - ty; } } int wdth = bx - tx; int hght = by - ty; // create an image of the grid area byte[] grid_img = image.createSubImage(img, img_width, img_height, bytes_per_pixel, tx, ty, bx, by); // get the orientation of the perimeter float dominant_orientation = perimeter.GetSquareOrientation(); // find the horizontal and vertical dimensions of the grid perimeter float grid_horizontal = perimeter.GetSquareHorizontal(); float grid_vertical = perimeter.GetSquareVertical(); // detect grid within the perimeter int cells_horizontal = 0, cells_vertical = 0; float horizontal_phase_offset = 0; float vertical_phase_offset = 0; if (spot_centres == null) DetectGrid(grid_img, wdth, hght, bytes_per_pixel, dominant_orientation, known_grid_spacing, grid_horizontal, grid_vertical, minimum_dimension_horizontal, maximum_dimension_horizontal, minimum_dimension_vertical, maximum_dimension_vertical, horizontal_scale_spacings, vertical_scale_spacings, ref average_spacing_horizontal, ref average_spacing_vertical, ref horizontal_phase_offset, ref vertical_phase_offset, ref cells_horizontal, ref cells_vertical, ref output_img, img_width, img_height, output_img_type); else DetectGrid(spot_centres, grid_img, wdth, hght, bytes_per_pixel, dominant_orientation, known_grid_spacing, grid_horizontal, grid_vertical, minimum_dimension_horizontal, maximum_dimension_horizontal, minimum_dimension_vertical, maximum_dimension_vertical, horizontal_scale_spacings, vertical_scale_spacings, ref average_spacing_horizontal, ref average_spacing_vertical, ref horizontal_phase_offset, ref vertical_phase_offset, ref cells_horizontal, ref cells_vertical, ref output_img, img_width, img_height, output_img_type); grid2D detectedGrid = null; // apply some range limits bool range_limited = false; if (cells_horizontal < 3) { cells_horizontal = 3; range_limited = true; } if (cells_vertical < 3) { cells_vertical = 3; range_limited = true; } if (cells_horizontal > maximum_dimension_horizontal) { cells_horizontal = maximum_dimension_horizontal; range_limited = true; } if (cells_vertical > maximum_dimension_vertical) { cells_vertical = maximum_dimension_vertical; range_limited = true; } if (range_limited) { Console.WriteLine("WARNING: When detecting the grid the matrix dimension had to be artificially restricted."); Console.WriteLine(" This probably means that there is a problem with the original image"); } // if we know the number of cells should be even correct any inaccuracies if (known_even_dimension) { cells_horizontal = (int)(cells_horizontal / 2) * 2; cells_vertical = (int)(cells_vertical / 2) * 2; } // get the centre of the region float cx = tx + ((bx - tx) / 2); float cy = ty + ((by - ty) / 2); detectedGrid = new grid2D(cells_horizontal, cells_vertical, cx, cy, dominant_orientation, average_spacing_horizontal, average_spacing_vertical, horizontal_phase_offset, vertical_phase_offset, border_cells); return (detectedGrid); }
private void init(int dimension_x, int dimension_y, polygon2D perimeter, int border_cells) { this.perimeter = perimeter; cell = new grid2Dcell[dimension_x, dimension_y]; line = new ArrayList[2]; int index = 0; for (int i = 0; i < 2; i++) { line[i] = new ArrayList(); int idx1 = index + i; if (idx1 >= 4) idx1 -= 4; int idx2 = index + i + 1; if (idx2 >= 4) idx2 -= 4; float x0 = (float)perimeter.x_points[idx1]; float y0 = (float)perimeter.y_points[idx1]; float x1 = (float)perimeter.x_points[idx2]; float y1 = (float)perimeter.y_points[idx2]; float w0 = Math.Abs(x1 - x0); float h0 = Math.Abs(y1 - y0); int idx3 = index + i + 2; if (idx3 >= 4) idx3 -= 4; int idx4 = index + i + 3; if (idx4 >= 4) idx4 -= 4; float x2 = (float)perimeter.x_points[idx3]; float y2 = (float)perimeter.y_points[idx3]; float x3 = (float)perimeter.x_points[idx4]; float y3 = (float)perimeter.y_points[idx4]; float w1 = Math.Abs(x3 - x2); float h1 = Math.Abs(y3 - y2); int dimension = dimension_x; if (h0 > w0) dimension = dimension_y; for (int j = -border_cells; j <= dimension + border_cells; j++) { // locate the position along the first line float xx0, yy0; // position along the first line if (w0 > h0) { float grad = (y1 - y0) / (x1 - x0); if (x1 > x0) xx0 = x0 + (w0 * j / dimension); else xx0 = x0 - (w0 * j / dimension); yy0 = y0 + ((xx0 - x0) * grad); } else { float grad = (x1 - x0) / (y1 - y0); if (y1 > y0) yy0 = y0 + (h0 * j / dimension); else yy0 = y0 - (h0 * j / dimension); xx0 = x0 + ((yy0 - y0) * grad); } // locate the position along the second line float xx1, yy1; // position along the second line if (w1 > h1) { float grad = (y2 - y3) / (x2 - x3); if (x2 > x3) xx1 = x3 + (w1 * j / dimension); else xx1 = x3 - (w1 * j / dimension); yy1 = y3 + ((xx1 - x3) * grad); } else { float grad = (x2 - x3) / (y2 - y3); if (y2 > y3) yy1 = y3 + (h1 * j / dimension); else yy1 = y3 - (h1 * j / dimension); xx1 = x3 + ((yy1 - y3) * grad); } // add the line to the list line[i].Add(xx0); line[i].Add(yy0); line[i].Add(xx1); line[i].Add(yy1); } } // find interceptions between lines poltLineIntercepts(); // create grid cells initialiseCells(); }
/// <summary> /// locates the centre position of a spot /// </summary> /// <param name="raw_image_mono">mono image data</param> /// <param name="raw_image_width">image width</param> /// <param name="raw_image_height">image height</param> /// <param name="search_region">region within which to search</param> /// <param name="black_on_white">whether this image contains dark markings on a lighter background</param> /// <param name="centre_x">returned x centre position</param> /// <param name="centre_y">returned y centre position</param> private static unsafe void LocateSpotCentre(byte *raw_image_mono, int raw_image_width, int raw_image_height, polygon2D search_region, bool black_on_white, ref float centre_x, ref float centre_y) { centre_x = 0; centre_y = 0; // get dimensions of the region to be searched int tx = (int)search_region.left(); //int ty = (int)search_region.top(); int bx = (int)search_region.right(); //int by = (int)search_region.bottom(); int r = (bx - tx) / 3; if (r < 1) { r = 1; } int search_r = (bx - tx) / 4; if (search_r < 1) { search_r = 1; } // centre of the search region float search_centre_x = 0; float search_centre_y = 0; search_region.GetSquareCentre(ref search_centre_x, ref search_centre_y); //search_region.getCentreOfGravity(ref search_centre_x, ref search_centre_y); int image_pixels = raw_image_width * raw_image_height; float max = 0; float v; for (float offset_y = search_centre_y - search_r; offset_y <= search_centre_y + search_r; offset_y += 0.5f) { for (float offset_x = search_centre_x - search_r; offset_x <= search_centre_x + search_r; offset_x += 0.5f) { float tot = 0; for (int yy = (int)(offset_y - r); yy <= (int)(offset_y + r); yy += 2) { int n0 = yy * raw_image_width; for (int xx = (int)(offset_x - r); xx <= (int)(offset_x + r); xx += 2) { int n1 = n0 + xx; if ((n1 > -1) && (n1 < image_pixels)) { if (black_on_white) { v = 255 - raw_image_mono[n1]; } else { v = raw_image_mono[n1]; } tot += v * v; } } } if (tot > max) { max = tot; centre_x = offset_x; centre_y = offset_y; } } } }
/// <summary> /// constructor /// </summary> /// <param name="dimension_x">number of cells across the grid</param> /// <param name="dimension_y">number of cells down the grid</param> /// <param name="cx">centre of the grid</param> /// <param name="cy">centre of the grid</param> /// <param name="orientation">orientation of the grid in radians</param> /// <param name="average_spacing_x">grid spacing in the x axis</param> /// <param name="average_spacing_y">grid spacing in the y axis</param> /// <param name="phase_offset_x">phase offset in the x axis</param> /// <param name="phase_offset_y">phase offset in the y axis</param> /// <param name="border_cells">number of cells to use as a border around the grid</param> public grid2D(int dimension_x, int dimension_y, float cx, float cy, float orientation, float average_spacing_x, float average_spacing_y, float phase_offset_x, float phase_offset_y, int border_cells, bool orientation_simple) { // create a perimeter region polygon2D perimeter = new polygon2D(); float length_x = average_spacing_x * dimension_x; float length_y = average_spacing_y * dimension_y; float half_length_x = length_x / 2; float half_length_y = length_y / 2; // adjust for phase cx += (average_spacing_x * phase_offset_x / (2 * (float)Math.PI)) * (float)Math.Sin(orientation); cy -= (average_spacing_y * phase_offset_y / (2 * (float)Math.PI)) * (float)Math.Cos(orientation); // find the mid point of the top line float px1 = cx + (half_length_y * (float)Math.Sin(orientation)); float py1 = cy + (half_length_y * (float)Math.Cos(orientation)); // find the top left vertex float x0 = px1 + (half_length_x * (float)Math.Sin(orientation - (float)(Math.PI / 2))); float y0 = py1 + (half_length_x * (float)Math.Cos(orientation - (float)(Math.PI / 2))); // find the top right vertex float x1 = px1 + (half_length_x * (float)Math.Sin(orientation + (float)(Math.PI / 2))); float y1 = py1 + (half_length_x * (float)Math.Cos(orientation + (float)(Math.PI / 2))); // find the bottom vertices by mirroring around the centre float x2 = cx + (cx - x0); float y2 = cy + (cy - y0); float x3 = cx - (x1 - cx); float y3 = cy - (y1 - cy); // update polygon with the perimeter vertices perimeter.Add(x0, y0); perimeter.Add(x1, y1); perimeter.Add(x2, y2); perimeter.Add(x3, y3); int dim_x = dimension_x; int dim_y = dimension_y; float first_side_length = perimeter.getSideLength(0); float second_side_length = perimeter.getSideLength(1); if (((dimension_x > dimension_y + 2) && (second_side_length > first_side_length)) || ((dimension_y > dimension_x + 2) && (first_side_length > second_side_length))) { dim_x = dimension_y; dim_y = dimension_x; } // initialise using this perimeter init(dim_x, dim_y, perimeter, border_cells, orientation_simple); }
/// <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); }
/// <summary> /// returns a copy of this polygon with each vetex randomly perturbed /// </summary> /// <param name="max_displacement"> /// maximum perturbation <see cref="System.Single"/> /// </param> /// <param name="rnd"> /// random number generator <see cref="Random"/> /// </param> /// <returns> /// polygon object <see cref="polygon2D"/> /// </returns> public polygon2D Jiggle(float max_displacement, Random rnd) { polygon2D result = null; if (x_points != null) { result = new polygon2D(); float max = max_displacement*2; for (int i = 0; i < x_points.Count; i++) { float jiggled_x = x_points[i] + ((float)rnd.NextDouble() * max) - max_displacement; float jiggled_y = x_points[i] + ((float)rnd.NextDouble() * max) - max_displacement; result.Add(jiggled_x, jiggled_y); } } return(result); }
/// <summary> /// constructor /// </summary> /// <param name="dimension_x">number of cells across the grid</param> /// <param name="dimension_y">number of cells down the grid</param> /// <param name="perimeter">perimeter of the grid</param> /// <param name="border_cells">number of cells to use as a border around the grid</param> public grid2D(int dimension_x, int dimension_y, polygon2D perimeter, int border_cells) { init(dimension_x, dimension_y, perimeter, border_cells); }
/// <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(x_points[i],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);
/// <summary> /// initialise the grid /// </summary> /// <param name="dimension_x"></param> /// <param name="dimension_y"></param> /// <param name="perimeter"></param> /// <param name="border_cells"></param> /// <param name="simple_orientation"></param> public void init(int dimension_x, int dimension_y, polygon2D perimeter, int border_cells, bool simple_orientation) { this.border_cells = border_cells; this.perimeter = perimeter; cell = new grid2Dcell[dimension_x][]; for (int x = 0; x < dimension_x; x++) cell[x] = new grid2Dcell[dimension_y]; line = new ArrayList[2]; float length3, length4; int index = 0; for (int i = 0; i < 2; i++) { line[i] = new ArrayList(); int idx1 = index + i; if (idx1 >= 4) idx1 -= 4; int idx2 = index + i + 1; if (idx2 >= 4) idx2 -= 4; float x0 = (float)perimeter.x_points[idx1]; float y0 = (float)perimeter.y_points[idx1]; float x1 = (float)perimeter.x_points[idx2]; float y1 = (float)perimeter.y_points[idx2]; int next_idx1 = idx1 + 1; if (next_idx1 >= 4) next_idx1 -= 4; length3 = perimeter.getSideLength(next_idx1); float w0 = Math.Abs(x1 - x0); float h0 = Math.Abs(y1 - y0); int idx3 = index + i + 2; if (idx3 >= 4) idx3 -= 4; int idx4 = index + i + 3; if (idx4 >= 4) idx4 -= 4; float x2 = (float)perimeter.x_points[idx3]; float y2 = (float)perimeter.y_points[idx3]; float x3 = (float)perimeter.x_points[idx4]; float y3 = (float)perimeter.y_points[idx4]; int next_idx3 = next_idx1 + 2; if (next_idx3 >= 4) next_idx3 -= 4; length4 = perimeter.getSideLength(next_idx3); float w1 = Math.Abs(x3 - x2); float h1 = Math.Abs(y3 - y2); int dimension = dimension_x; if (!simple_orientation) { if (i > 0) dimension = dimension_y; } else { if (h0 > w0) dimension = dimension_y; } // how much shorter is one line than the other on the opposite axis? float shortening = 0; //if (h0 > w0) { if (length3 > length4) shortening = (length3 - length4) / length3; else shortening = (length4 - length3) / length4; } for (int j = -border_cells; j <= dimension + border_cells; j++) { // locate the position along the first line float xx0, yy0; // position along the first line float fraction = j / (float)dimension; // modify for foreshortening //if ((h0 > w0) && (shortening > 0)) if (shortening > 0) { fraction = (fraction * (1.0f - shortening)) + ((float)Math.Sin(fraction * (float)Math.PI / 2) * shortening); if (length3 > length4) fraction = 1.0f - fraction; } if (w0 > h0) { float grad = (y1 - y0) / (x1 - x0); if (x1 > x0) xx0 = x0 + (w0 * fraction); else xx0 = x0 - (w0 * fraction); yy0 = y0 + ((xx0 - x0) * grad); } else { float grad = (x1 - x0) / (y1 - y0); if (y1 > y0) yy0 = y0 + (h0 * fraction); else yy0 = y0 - (h0 * fraction); xx0 = x0 + ((yy0 - y0) * grad); } // locate the position along the second line float xx1, yy1; // position along the second line if (w1 > h1) { float grad = (y2 - y3) / (x2 - x3); if (x2 > x3) xx1 = x3 + (w1 * fraction); else xx1 = x3 - (w1 * fraction); yy1 = y3 + ((xx1 - x3) * grad); } else { float grad = (x2 - x3) / (y2 - y3); if (y2 > y3) yy1 = y3 + (h1 * fraction); else yy1 = y3 - (h1 * fraction); xx1 = x3 + ((yy1 - y3) * grad); } // add the line to the list line[i].Add(xx0); line[i].Add(yy0); line[i].Add(xx1); line[i].Add(yy1); } } // find interceptions between lines poltLineIntercepts(); // create grid cells initialiseCells(); }
/// <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(x_points[i] * 1000 / image_width, 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);
/// <summary> /// returns the difference in the positions of vertices /// compared to another polygon /// </summary> /// <param name="other">the other polygon</param> /// <returns></returns> public float Compare(polygon2D other) { float difference = 0; // vertices exist if ((x_points != null) && (other.x_points != null)) { // same number of vertices if (x_points.Count == other.x_points.Count) { for (int i = 0; i < x_points.Count; i++) { float dx = Math.Abs(x_points[i] - other.x_points[i]); float dy = Math.Abs(y_points[i] - other.y_points[i]); difference += dx + dy; } } } return (difference);
/// <summary> /// finds the interception points between grid lines /// </summary> private void poltLineIntercepts() { if (line != null) { // create an array to store the line intercepts int intercepts_x = line[0].Count/4; int intercepts_y = line[1].Count/4; line_intercepts = new float[intercepts_x, intercepts_y, 2]; for (int i = 0; i < line[0].Count; i += 4) { // get the first line coordinates ArrayList lines0 = line[0]; float x0 = (float)lines0[i]; float y0 = (float)lines0[i + 1]; float x1 = (float)lines0[i + 2]; float y1 = (float)lines0[i + 3]; for (int j = 0; j < line[1].Count; j += 4) { // get the second line coordinates ArrayList lines1 = line[1]; float x2 = (float)lines1[j]; float y2 = (float)lines1[j + 1]; float x3 = (float)lines1[j + 2]; float y3 = (float)lines1[j + 3]; // find the interception between the two lines float ix = 0, iy = 0; geometry.intersection(x0, y0, x1, y1, x2, y2, x3, y3, ref ix, ref iy); // store the intercept position line_intercepts[i/4, j/4, 0] = ix; line_intercepts[i/4, j/4, 1] = iy; } } // update the perimeter border_perimeter = new polygon2D(); float xx = line_intercepts[0, 0, 0]; float yy = line_intercepts[0, 0, 1]; border_perimeter.Add(xx, yy); xx = line_intercepts[intercepts_x - 1, 0, 0]; yy = line_intercepts[intercepts_x - 1, 0, 1]; border_perimeter.Add(xx, yy); xx = line_intercepts[intercepts_x - 1, intercepts_y - 1, 0]; yy = line_intercepts[intercepts_x - 1, intercepts_y - 1, 1]; border_perimeter.Add(xx, yy); xx = line_intercepts[0, intercepts_y - 1, 0]; yy = line_intercepts[0, intercepts_y - 1, 1]; border_perimeter.Add(xx, yy); } }
/// <summary> /// snaps the vertices of the polygon to a grid having the given spacing /// </summary> /// <param name="grid_spacing">spacing of the grid</param> /// <returns>fitted polygon</returns> public polygon2D SnapToGrid(float grid_spacing) { polygon2D result = new polygon2D(); if (x_points != null) { for (int i = 0; i < x_points.Count; i++) { float x = x_points[i] / grid_spacing; x = (float)Math.Round(x) * grid_spacing; float y = y_points[i] / grid_spacing; y = (float)Math.Round(y) * grid_spacing; result.Add(x, y); } } return (result);
/// <summary> /// returns an ideally spaced grid over the actual detected spots /// </summary> /// <param name="grid"></param> /// <returns></returns> private static grid2D OverlayIdealGrid(CalibrationDot[,] grid, List<CalibrationDot> corners, ref int grid_offset_x, ref int grid_offset_y, int random_seed) { grid2D overlay_grid = null; int grid_tx = -1; int grid_ty = -1; int grid_bx = -1; int grid_by = -1; int offset_x = 0; int offset_y = 0; bool found = false; int max_region_area = 0; // try searching horizontally and vertically // then pick the result with the greatest area for (int test_orientation = 0; test_orientation < 2; test_orientation++) { bool temp_found = false; int temp_grid_tx = -1; int temp_grid_ty = -1; int temp_grid_bx = -1; int temp_grid_by = -1; int temp_offset_x = 0; int temp_offset_y = 0; switch (test_orientation) { case 0: { while ((temp_offset_y < 5) && (!temp_found)) { temp_offset_x = 0; while ((temp_offset_x < 3) && (!temp_found)) { temp_grid_tx = temp_offset_x; temp_grid_ty = temp_offset_y; temp_grid_bx = grid.GetLength(0) - 1 - temp_offset_x; temp_grid_by = grid.GetLength(1) - 1 - temp_offset_y; if ((temp_grid_bx < grid.GetLength(0)) && (temp_grid_tx < grid.GetLength(0)) && (temp_grid_by < grid.GetLength(1)) && (temp_grid_ty < grid.GetLength(1)) && (temp_grid_ty >= 0) && (temp_grid_by >= 0) && (temp_grid_tx >= 0) && (temp_grid_bx >= 0)) { if ((grid[temp_grid_tx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_by] != null) && (grid[temp_grid_tx, temp_grid_by] != null)) { temp_found = true; } } temp_offset_x++; } temp_offset_y++; } break; } case 1: { while ((temp_offset_x < 3) && (!temp_found)) { temp_offset_y = 0; while ((temp_offset_y < 5) && (!temp_found)) { temp_grid_tx = temp_offset_x; temp_grid_ty = temp_offset_y; temp_grid_bx = grid.GetLength(0) - 1 - temp_offset_x; temp_grid_by = grid.GetLength(1) - 1 - temp_offset_y; if ((temp_grid_bx < grid.GetLength(0)) && (temp_grid_tx < grid.GetLength(0)) && (temp_grid_by < grid.GetLength(1)) && (temp_grid_ty < grid.GetLength(1)) && (temp_grid_ty >= 0) && (temp_grid_by >= 0) && (temp_grid_tx >= 0) && (temp_grid_bx >= 0)) { if ((grid[temp_grid_tx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_by] != null) && (grid[temp_grid_tx, temp_grid_by] != null)) { temp_found = true; } } temp_offset_y++; } temp_offset_x++; } break; } } temp_offset_y = temp_grid_ty - 1; while (temp_offset_y >= 0) { if ((temp_offset_y < grid.GetLength(1)) && (temp_offset_y >= 0)) { if ((grid[temp_grid_tx, temp_offset_y] != null) && (grid[temp_grid_bx, temp_offset_y] != null)) { temp_grid_ty = temp_offset_y; temp_offset_y--; } else break; } else break; } temp_offset_y = temp_grid_by + 1; while (temp_offset_y < grid.GetLength(1)) { if ((temp_offset_y < grid.GetLength(1)) && (temp_offset_y >= 0)) { if ((grid[temp_grid_tx, temp_offset_y] != null) && (grid[temp_grid_bx, temp_offset_y] != null)) { temp_grid_by = temp_offset_y; temp_offset_y++; } else break; } else break; } if (temp_found) { int region_area = (temp_grid_bx - temp_grid_tx) * (temp_grid_by - temp_grid_ty); if (region_area > max_region_area) { max_region_area = region_area; found = true; grid_tx = temp_grid_tx; grid_ty = temp_grid_ty; grid_bx = temp_grid_bx; grid_by = temp_grid_by; offset_x = temp_offset_x; offset_y = temp_offset_y; } } } if (found) { // record the positions of the corners corners.Add(grid[grid_tx, grid_ty]); corners.Add(grid[grid_bx, grid_ty]); corners.Add(grid[grid_bx, grid_by]); corners.Add(grid[grid_tx, grid_by]); double dx, dy; double x0 = grid[grid_tx, grid_ty].x; double y0 = grid[grid_tx, grid_ty].y; double x1 = grid[grid_bx, grid_ty].x; double y1 = grid[grid_bx, grid_ty].y; double x2 = grid[grid_tx, grid_by].x; double y2 = grid[grid_tx, grid_by].y; double x3 = grid[grid_bx, grid_by].x; double y3 = grid[grid_bx, grid_by].y; polygon2D perimeter = new polygon2D(); perimeter.Add((float)x0, (float)y0); perimeter.Add((float)x1, (float)y1); perimeter.Add((float)x3, (float)y3); perimeter.Add((float)x2, (float)y2); int grid_width = grid_bx - grid_tx; int grid_height = grid_by - grid_ty; int min_hits = 0; double min_dx = 0, min_dy = 0; // try various perimeter sizes double min_dist = double.MaxValue; int max_perim_size_tries = 100; polygon2D best_perimeter = perimeter; Random rnd = new Random(random_seed); for (int perim_size = 0; perim_size < max_perim_size_tries; perim_size++) { // try a small range of translations for (int nudge_x = -10; nudge_x <= 10; nudge_x++) { for (int nudge_y = -5; nudge_y <= 5; nudge_y++) { // create a perimeter at this scale and translation polygon2D temp_perimeter = perimeter.Scale(1.0f + (perim_size * 0.1f / max_perim_size_tries)); temp_perimeter = temp_perimeter.ScaleSideLength(0, 0.95f + ((float)rnd.NextDouble() * 0.1f)); temp_perimeter = temp_perimeter.ScaleSideLength(2, 0.95f + ((float)rnd.NextDouble() * 0.1f)); for (int i = 0; i < temp_perimeter.x_points.Count; i++) { temp_perimeter.x_points[i] += nudge_x; temp_perimeter.y_points[i] += nudge_y; } // create a grid based upon the perimeter grid2D temp_overlay_grid = new grid2D(grid_width, grid_height, temp_perimeter, 0, false); // how closely does the grid fit the actual observations ? double temp_min_dist = min_dist; BestFit(grid_tx, grid_ty, grid, temp_overlay_grid, ref min_dist, ref min_dx, ref min_dy, ref min_hits, ref grid_offset_x, ref grid_offset_y); // record the closest fit if (temp_min_dist < min_dist) { best_perimeter = temp_perimeter; overlay_grid = temp_overlay_grid; } } } } if (min_hits > 0) { dx = min_dx; dy = min_dy; Console.WriteLine("dx: " + dx.ToString()); Console.WriteLine("dy: " + dy.ToString()); x0 += dx; y0 += dy; x1 += dx; y1 += dy; x2 += dx; y2 += dy; x3 += dx; y3 += dy; perimeter = new polygon2D(); perimeter.Add((float)x0, (float)y0); perimeter.Add((float)x1, (float)y1); perimeter.Add((float)x3, (float)y3); perimeter.Add((float)x2, (float)y2); overlay_grid = new grid2D(grid_width, grid_height, perimeter, 0, false); } } return (overlay_grid); }
/// <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 = x_points[i] - centre_x; float dy = 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); }
/// <summary> /// detects a square around the centre dot on the calibration pattern /// </summary> /// <param name="dots">detected dots</param> /// <param name="centredots">returned dots belonging to the centre square</param> /// <returns>centre square</returns> private static polygon2D GetCentreSquare(hypergraph dots, ref List<CalibrationDot> centredots) { centredots = new List<CalibrationDot>(); // find the centre dot CalibrationDot centre = null; int i = 0; while ((i < dots.Nodes.Count) && (centre == null)) { CalibrationDot dot = (CalibrationDot)dots.Nodes[i]; if (dot.centre) centre = dot; i++; } // look for the four surrounding dots List<CalibrationDot> centre_dots = new List<CalibrationDot>(); List<double> distances = new List<double>(); i = 0; for (i = 0; i < dots.Nodes.Count; i++) { CalibrationDot dot = (CalibrationDot)dots.Nodes[i]; if (!dot.centre) { double dx = dot.x - centre.x; double dy = dot.y - centre.y; double dist = Math.Sqrt(dx * dx + dy * dy); if (distances.Count == 4) { int index = -1; double max_dist = 0; for (int j = 0; j < 4; j++) { if (distances[j] > max_dist) { index = j; max_dist = distances[j]; } } if (dist < max_dist) { distances[index] = dist; centre_dots[index] = dot; } } else { distances.Add(dist); centre_dots.Add(dot); } } } polygon2D centre_square = null; if (centre_dots.Count == 4) { centre_square = new polygon2D(); for (i = 0; i < 4; i++) centre_square.Add(0, 0); double xx = centre.x; double yy = centre.y; int index = 0; for (i = 0; i < 4; i++) { if ((centre_dots[i].x < xx) && (centre_dots[i].y < yy)) { xx = centre_dots[i].x; yy = centre_dots[i].y; centre_square.x_points[0] = (float)xx; centre_square.y_points[0] = (float)yy; index = i; } } centredots.Add(centre_dots[index]); xx = centre.x; yy = centre.y; for (i = 0; i < 4; i++) { if ((centre_dots[i].x > xx) && (centre_dots[i].y < yy)) { xx = centre_dots[i].x; yy = centre_dots[i].y; centre_square.x_points[1] = (float)xx; centre_square.y_points[1] = (float)yy; index = i; } } centredots.Add(centre_dots[index]); xx = centre.x; yy = centre.y; for (i = 0; i < 4; i++) { if ((centre_dots[i].x > xx) && (centre_dots[i].y > yy)) { xx = centre_dots[i].x; yy = centre_dots[i].y; centre_square.x_points[2] = (float)xx; centre_square.y_points[2] = (float)yy; index = i; } } centredots.Add(centre_dots[index]); xx = centre.x; yy = centre.y; for (i = 0; i < 4; i++) { if ((centre_dots[i].x < xx) && (centre_dots[i].y > yy)) { xx = centre_dots[i].x; yy = centre_dots[i].y; centre_square.x_points[3] = (float)xx; centre_square.y_points[3] = (float)yy; index = i; } } centredots.Add(centre_dots[index]); } return (centre_square); }
/// <summary> /// scale the polygon to a new image size /// </summary> /// <param name="original_image_width"></param> /// <param name="original_image_height"></param> /// <param name="new_image_width"></param> /// <param name="new_image_height"></param> /// <returns></returns> public polygon2D Scale(int original_image_width, int original_image_height, int new_image_width, int new_image_height) { polygon2D rescaled = new polygon2D(); for (int i = 0; i < x_points.Count; i++) { float x = x_points[i] * new_image_width / original_image_width; float y = y_points[i] * new_image_height / original_image_height; rescaled.Add(x, y); } return (rescaled); }