private static void DetectLensDistortion(int image_width, int image_height, calibrationDot[,] grid, grid2D overlay_grid, List<List<double>> lines, ref polynomial curve, ref calibrationDot centre_of_distortion, ref List<List<double>> best_rectified_lines, int grid_offset_x, int grid_offset_y, double scale, ref double minimum_error, int random_seed) { double centre_of_distortion_search_radius = image_width / 100f; //80.0f; centre_of_distortion = new calibrationDot(); curve = FitCurve(image_width, image_height, grid, overlay_grid, centre_of_distortion, centre_of_distortion_search_radius, grid_offset_x, grid_offset_y, lines, ref minimum_error, random_seed); if (curve != null) { double rotation = 0; best_rectified_lines = RectifyLines(lines, image_width, image_height, curve, centre_of_distortion, rotation, scale); } }
/// <summary> /// shows the perimeter of the ideal rectified grid /// </summary> /// <param name="filename">raw image filename</param> /// <param name="overlay_grid">ideal rectified grid</param> /// <param name="output_filename">filename to save as</param> private static void ShowOverlayGridPerimeter(string filename, grid2D overlay_grid, string output_filename) { Bitmap bmp = (Bitmap)Bitmap.FromFile(filename); byte[] img = new byte[bmp.Width * bmp.Height * 3]; BitmapArrayConversions.updatebitmap(bmp, img); if (overlay_grid != null) { overlay_grid.perimeter.show(img, bmp.Width, bmp.Height, 255, 0, 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); }
private static void BestFit(int grid_tx, int grid_ty, calibrationDot[,] grid, grid2D overlay_grid, ref double min_dist, ref double min_dx, ref double min_dy, ref int min_hits, ref int grid_offset_x, ref int grid_offset_y) { for (int off_x = -1; off_x <= 1; off_x++) { for (int off_y = -1; off_y <= 1; off_y++) { int grid_x_offset = -grid_tx + off_x; int grid_y_offset = -grid_ty + off_y; int grid_x_offset_start = 0; int grid_x_offset_end = 0; if (grid_x_offset < 0) { grid_x_offset_start = -grid_x_offset; grid_x_offset_end = 0; } else { grid_x_offset_start = 0; grid_x_offset_end = grid_x_offset; } int grid_y_offset_start = 0; int grid_y_offset_end = 0; if (grid_y_offset < 0) { grid_y_offset_start = -grid_y_offset; grid_y_offset_end = 0; } else { grid_y_offset_start = 0; grid_y_offset_end = grid_y_offset; } double dx = 0; double dy = 0; double dist = 0; int hits = 0; for (int grid_x = grid_x_offset_start; grid_x < grid.GetLength(0) - grid_x_offset_end; grid_x++) { for (int grid_y = grid_y_offset_start; grid_y < grid.GetLength(1) - grid_y_offset_end; grid_y++) { if (grid[grid_x, grid_y] != null) { if ((grid_x + grid_x_offset < overlay_grid.line_intercepts.GetLength(0)) && (grid_y + grid_y_offset < overlay_grid.line_intercepts.GetLength(1))) { double intercept_x = overlay_grid.line_intercepts[grid_x + grid_x_offset, grid_y + grid_y_offset, 0]; double intercept_y = overlay_grid.line_intercepts[grid_x + grid_x_offset, grid_y + grid_y_offset, 1]; double dxx = grid[grid_x, grid_y].x - intercept_x; double dyy = grid[grid_x, grid_y].y - intercept_y; dx += dxx; dy += dyy; dist += Math.Abs(dxx) + Math.Abs(dyy); hits++; } } } } if (hits > 0) { dx /= hits; dy /= hits; //double dist = Math.Sqrt(dx * dx + dy * dy); if (dist < min_dist) { min_dist = dist; min_dx = dx; min_dy = dy; min_hits = hits; grid_offset_x = grid_x_offset; grid_offset_y = grid_y_offset; } } } } }
/// <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; MersenneTwister rnd = new MersenneTwister(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> /// fits a curve to the given grid using the given centre of distortion /// </summary> /// <param name="grid">detected grid dots</param> /// <param name="overlay_grid">overlayed ideal rectified grid</param> /// <param name="centre_of_distortion">centre of lens distortion</param> /// <param name="curve">curve to be fitted</param> private static void FitCurve(calibrationDot[,] grid, grid2D overlay_grid, calibrationDot centre_of_distortion, polynomial curve, double noise, MersenneTwister rnd, int grid_offset_x, int grid_offset_y) { double[] prev_col = new double[grid.GetLength(1) * 2]; double[] col = new double[prev_col.Length]; double half_noise = noise / 2; double rectified_x, rectified_y; for (int pass = 0; pass < 1; pass++) { // for every detected dot for (int grid_x = 0; grid_x < grid.GetLength(0); grid_x++) { double prev_rectified_radial_dist = 0; double prev_actual_radial_dist = 0; int prev_grid_y = -1; for (int grid_y = 0; grid_y < grid.GetLength(1); grid_y++) { if (grid[grid_x, grid_y] != null) { if ((grid_x + grid_offset_x < overlay_grid.line_intercepts.GetLength(0)) && (grid_y + grid_offset_y < overlay_grid.line_intercepts.GetLength(1)) && (grid_x + grid_offset_x >= 0) && (grid_y + grid_offset_y >= 0)) { // find the rectified distance of the dot from the centre of distortion rectified_x = overlay_grid.line_intercepts[grid_x + grid_offset_x, grid_y + grid_offset_y, 0]; rectified_y = overlay_grid.line_intercepts[grid_x + grid_offset_x, grid_y + grid_offset_y, 1]; if (pass > 0) { rectified_x += (((rnd.NextDouble() * noise) - half_noise) * 0.1); rectified_y += (((rnd.NextDouble() * noise) - half_noise) * 0.1); } //double rectified_x = overlay_grid.line_intercepts[grid_x + grid_offset_x, grid_y + grid_offset_y, 0]; //double rectified_y = overlay_grid.line_intercepts[grid_x + grid_offset_x, grid_y + grid_offset_y, 1]; double rectified_dx = rectified_x - centre_of_distortion.x; double rectified_dy = rectified_y - centre_of_distortion.y; double rectified_radial_dist = Math.Sqrt(rectified_dx * rectified_dx + rectified_dy * rectified_dy); // find the actual raw image distance of the dot from the centre of distortion //double actual_x = grid[grid_x, grid_y].x + (((rnd.NextDouble() * noise) - half_noise) * 2); //double actual_y = grid[grid_x, grid_y].y + (((rnd.NextDouble() * noise) - half_noise) * 2); double actual_x = grid[grid_x, grid_y].x; double actual_y = grid[grid_x, grid_y].y; double actual_dx = actual_x - centre_of_distortion.x; double actual_dy = actual_y - centre_of_distortion.y; double actual_radial_dist = Math.Sqrt(actual_dx * actual_dx + actual_dy * actual_dy); // plot curve.AddPoint(rectified_radial_dist, actual_radial_dist); col[(grid_y * 2)] = rectified_radial_dist; col[(grid_y * 2) + 1] = actual_radial_dist; prev_rectified_radial_dist = rectified_radial_dist; prev_actual_radial_dist = actual_radial_dist; prev_grid_y = grid_y; } } } for (int i = 0; i < col.Length; i++) prev_col[i] = col[i]; } } // find the best fit curve curve.Solve(); }
/// <summary> /// fits a curve to the given grid using the given centre of distortion /// </summary> /// <param name="image_width">width of the image in pixels</param> /// <param name="image_height">height of the image in pixels</param> /// <param name="grid">detected grid dots</param> /// <param name="overlay_grid">overlayed ideal rectified grid</param> /// <param name="centre_of_distortion">centre of lens distortion</param> /// <param name="centre_of_distortion_search_radius">search radius for the centre of distortion</param> /// <returns>fitted curve</returns> private static polynomial FitCurve(int image_width, int image_height, calibrationDot[,] grid, grid2D overlay_grid, calibrationDot centre_of_distortion, double centre_of_distortion_search_radius, int grid_offset_x, int grid_offset_y, List<List<double>> lines, ref double minimum_error, int random_seed) { double overall_minimum_error = double.MaxValue; double centre_of_distortion_x=0, centre_of_distortion_y=0; polynomial overall_best_curve = null; polynomial best_curve = null; for (int rand_pass = random_seed; rand_pass < random_seed + 3; rand_pass++) { minimum_error = double.MaxValue; double search_min_error = minimum_error; int degrees = 3; int best_degrees = degrees; List<double> prev_minimum_error = new List<double>(); prev_minimum_error.Add(minimum_error); double increment = 3.0f; double noise = increment / 2; best_curve = null; double search_radius = (float)centre_of_distortion_search_radius; double half_width = image_width / 2; double half_height = image_height / 2; double half_noise = noise / 2; double max_radius_sqr = centre_of_distortion_search_radius * centre_of_distortion_search_radius; int scaled_up = 0; List<double> result = new List<double>(); double best_cx = half_width, best_cy = half_height; float maxerr = (image_width / 2) * (image_width / 2); MersenneTwister rnd = new MersenneTwister(rand_pass); int max_passes = 1000; for (int pass = 0; pass < max_passes; pass++) { double centre_x = 0; double centre_y = 0; double mass = 0; for (double cx = half_width - search_radius; cx < half_width + search_radius; cx += increment) { double dx = cx - half_width; for (double cy = half_height - search_radius; cy < half_height + search_radius; cy += increment) { double dy = cy - half_height; double dist = dx * dx + dy * dy; if (dist < max_radius_sqr) { polynomial curve = new polynomial(); curve.SetDegree(degrees); centre_of_distortion.x = cx + (rnd.NextDouble() * noise) - half_noise; centre_of_distortion.y = cy + (rnd.NextDouble() * noise) - half_noise; FitCurve(grid, overlay_grid, centre_of_distortion, curve, noise, rnd, grid_offset_x, grid_offset_y); // do a sanity check on the curve if (ValidCurve(curve, image_width)) { double error = curve.GetMeanError(); error = error * error; if (error > 0.001) { error = maxerr - error; // inverse if (error > 0) { centre_x += centre_of_distortion.x * error; centre_y += centre_of_distortion.y * error; mass += error; } } } } } } if (mass > 0) { centre_x /= mass; centre_y /= mass; centre_of_distortion.x = centre_x; centre_of_distortion.y = centre_y; polynomial curve2 = new polynomial(); curve2.SetDegree(degrees); FitCurve(grid, overlay_grid, centre_of_distortion, curve2, noise, rnd, grid_offset_x, grid_offset_y); double mean_error = curve2.GetMeanError(); double scaledown = 0.99999999999999999; if (mean_error < search_min_error) { search_min_error = mean_error; // cool down prev_minimum_error.Add(search_min_error); search_radius *= scaledown; increment *= scaledown; noise = increment / 2; half_noise = noise / 2; half_width = centre_x; half_height = centre_y; if (mean_error < minimum_error) { best_cx = half_width; best_cy = half_height; minimum_error = mean_error; Console.WriteLine("Cool " + pass.ToString() + ": " + mean_error.ToString()); if (max_passes - pass < 500) max_passes += 500; best_degrees = degrees; best_curve = curve2; } scaled_up = 0; } else { // heat up double scaleup = 1.0 / scaledown; search_radius /= scaledown; increment /= scaledown; noise = increment / 2; half_noise = noise / 2; scaled_up++; half_width = best_cx + (rnd.NextDouble() * noise) - half_noise; half_height = best_cy + (rnd.NextDouble() * noise) - half_noise; if (prev_minimum_error.Count > 0) { minimum_error = prev_minimum_error[prev_minimum_error.Count - 1]; prev_minimum_error.RemoveAt(prev_minimum_error.Count - 1); } } result.Add(mean_error); } } minimum_error = Math.Sqrt(minimum_error); centre_of_distortion.x = best_cx; centre_of_distortion.y = best_cy; if (best_curve != null) minimum_error = best_curve.GetMeanError(); if (minimum_error < overall_minimum_error) { overall_minimum_error = minimum_error; centre_of_distortion_x = best_cx; centre_of_distortion_y = best_cy; overall_best_curve = best_curve; } } overall_minimum_error = minimum_error; centre_of_distortion.x = centre_of_distortion_x; centre_of_distortion.y = centre_of_distortion_y; best_curve = overall_best_curve; return (best_curve); }
/// <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> /// <param name="average_spacing_horizontal"></param> /// <param name="average_spacing_vertical"></param> /// <param name="output_img"></param> /// <param name="output_img_width"></param> /// <param name="output_img_height"></param> /// <param name="output_img_type"></param> /// <param name="ideal_grid_colour">colour used to draw the ideal grid</param> /// <param name="detected_grid_colour">colour used to draw the detected grid</param> /// <param name="simple_orientation"></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_width, int output_img_height, int output_img_type, byte[] ideal_grid_colour, byte[] detected_grid_colour, bool simple_orientation) { 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, output_img_width, output_img_height, output_img_type, ideal_grid_colour, detected_grid_colour); 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, output_img_width, output_img_height, output_img_type, ideal_grid_colour, detected_grid_colour); 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, simple_orientation); return (detectedGrid); }
/// <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> /// 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); }