Пример #1
0
        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);
            }
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        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;
                        }

                    }
                }
            }
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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();
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        /// <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);
        }
Пример #9
0
        /// <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);
        }