int run_program(int argc, char **argv) { CommandLineArgument<std::string> points_pathname; Configuration cfg; cfg.width = 640; cfg.height = 480; cfg.window_title = ""; cfg.circle_radius = 2; cfg.circle_thickness = 1; cfg.circle_linetype = 8; cfg.circle_shift = 0; cfg.circle_colour = cv::Scalar(0, 0, 255); for (int i = 1; i < argc; i++) { std::string argument(argv[i]); if (argument == "--help") { print_usage(); return 0; } else if (argument == "--width") { cfg.width = get_argument<int>(&i, argc, argv); } else if (argument == "--height") { cfg.height = get_argument<int>(&i, argc, argv); } else if (argument == "--window-title") { cfg.window_title = get_argument(&i, argc, argv); } else if (argument == "--circle-radius") { cfg.circle_radius = get_argument<int>(&i, argc, argv); } else if (!assign_argument(argument, points_pathname)) { throw make_runtime_error("Unable to process argument: %s\n", argument.c_str()); } } if (!have_argument_p(points_pathname)) { print_usage(); return -1; } if (cfg.window_title == "") cfg.window_title = points_pathname->c_str(); std::vector<cv::Point3_<double> > shape3D; try { shape3D = load_points3(points_pathname->c_str()); } catch (std::exception &e) { throw make_runtime_error("Encountered error when reading file '%s': %s", points_pathname->c_str(), e.what()); } cv::Point3_<double> mean = calculate_mean(shape3D); for (size_t i = 0; i < shape3D.size(); i++) { shape3D[i] -= mean; } cv::Mat_<double> projection = cv::Mat_<double>::eye(3,4); if (cfg.height < cfg.width) { projection(0,3) = double(cfg.width - cfg.height) / 2.0; } else { projection(1,3) = double(cfg.height - cfg.width) / 2.0; } cv::Mat_<double> starting_A = calculate_similarity_transform(shape3D, cfg.height, cfg.width); cv::Mat_<double> A(starting_A.clone()); bool quit = false; while (!quit) { int key = cv::waitKey(1); switch (key) { case 27: quit = true; break; case 'z': A = A * scaling_matrix(1.1); break; case 'x': A = A * scaling_matrix(0.9); break; case 'a': A = A * rotation_about_y_axis(-0.1); break; case 'd': A = A * rotation_about_y_axis(0.1); break; case 'w': A = A * rotation_about_x_axis(-0.1); break; case 's': A = A * rotation_about_x_axis(0.1); break; case 'q': A = A * rotation_about_z_axis(0.1); break; case 'e': A = A * rotation_about_z_axis(-0.1); break; case 'r': A = starting_A.clone(); break; } display_points(cfg, projection * A, shape3D); } return 0; }
//TODO: code here should be abstracted outside the app, modify tests accordingly int main(int argc, char *argv[]) { // Chec the number of arguments if (argc != 2) { std::cout << "********************************" << std::endl; std::cout << "Usage of the code: ./traffic-sign-detection imageFileName.extension" << std::endl; std::cout << "********************************" << std::endl; return -1; } // Clock for measuring the elapsed time std::chrono::time_point<std::chrono::system_clock> start, end; start = std::chrono::system_clock::now(); // Read the input image - convert char* to string std::string input_filename(argv[1]); // Read the input image cv::Mat input_image = cv::imread(input_filename); // Check that the image has been opened if (!input_image.data) { std::cout << "Error to read the image. Check ''cv::imread'' function of OpenCV" << std::endl; return -1; } // Check that the image read is a 3 channels image CV_Assert(input_image.channels() == 3); /* * Conversion of the image in some specific color space */ // Conversion of the rgb image in ihls color space cv::Mat ihls_image; colorconversion::convert_rgb_to_ihls(input_image, ihls_image); // Conversion from RGB to logarithmic chromatic red and blue std::vector< cv::Mat > log_image; colorconversion::rgb_to_log_rb(input_image, log_image); /* * Segmentation of the image using the previous transformation */ // Segmentation of the IHLS and more precisely of the normalised hue channel // ONE PARAMETER TO CONSIDER - COLOR OF THE TRAFFIC SIGN TO DETECT - RED VS BLUE int nhs_mode = 0; // nhs_mode == 0 -> red segmentation / nhs_mode == 1 -> blue segmentation cv::Mat nhs_image_seg_red; segmentation::seg_norm_hue(ihls_image, nhs_image_seg_red, nhs_mode); //nhs_mode = 1; // nhs_mode == 0 -> red segmentation / nhs_mode == 1 -> blue segmentation //cv::Mat nhs_image_seg_blue; cv::Mat nhs_image_seg_blue = nhs_image_seg_red.clone(); //segmentation::seg_norm_hue(ihls_image, nhs_image_seg_blue, nhs_mode); // Segmentation of the log chromatic image // TODO - DEFINE THE THRESHOLD FOR THE BLUE TRAFFIC SIGN. FOR NOW WE AVOID THE PROCESSING FOR BLUE SIGN AND LET ONLY THE OTHER METHOD TO TAKE CARE OF IT. cv::Mat log_image_seg; segmentation::seg_log_chromatic(log_image, log_image_seg); /* * Merging and filtering of the previous segmentation */ // Merge the results of previous segmentation using an OR operator // Pre-allocation of an image by cloning a previous image cv::Mat merge_image_seg_with_red = nhs_image_seg_red.clone(); cv::Mat merge_image_seg = nhs_image_seg_blue.clone(); cv::bitwise_or(nhs_image_seg_red, log_image_seg, merge_image_seg_with_red); cv::bitwise_or(nhs_image_seg_blue, merge_image_seg_with_red, merge_image_seg); // Filter the image using median filtering and morpho math cv::Mat bin_image; imageprocessing::filter_image(merge_image_seg, bin_image); cv::imwrite("seg.jpg", bin_image); /* * Extract candidates (i.e., contours) and remove inconsistent candidates */ std::vector< std::vector< cv::Point > > distorted_contours; imageprocessing::contours_extraction(bin_image, distorted_contours); /* * Correct the distortion for each contour */ // Initialisation of the variables which will be returned after the distortion. These variables are linked with the transformation applied to correct the distortion std::vector< cv::Mat > rotation_matrix(distorted_contours.size()); std::vector< cv::Mat > scaling_matrix(distorted_contours.size()); std::vector< cv::Mat > translation_matrix(distorted_contours.size()); for (unsigned int contour_idx = 0; contour_idx < distorted_contours.size(); contour_idx++) { rotation_matrix[contour_idx] = cv::Mat::eye(3, 3, CV_32F); scaling_matrix[contour_idx] = cv::Mat::eye(3, 3, CV_32F); translation_matrix[contour_idx] = cv::Mat::eye(3, 3, CV_32F); } // Correct the distortion std::vector< std::vector< cv::Point2f > > undistorted_contours; imageprocessing::correction_distortion(distorted_contours, undistorted_contours, translation_matrix, rotation_matrix, scaling_matrix); // Normalise the contours to be inside a unit circle std::vector<double> factor_vector(undistorted_contours.size()); std::vector< std::vector< cv::Point2f > > normalised_contours; initopt::normalise_all_contours(undistorted_contours, normalised_contours, factor_vector); std::vector< std::vector< cv::Point2f > > detected_signs_2f(normalised_contours.size()); std::vector< std::vector< cv::Point > > detected_signs(normalised_contours.size()); // For each contours for (unsigned int contour_idx = 0; contour_idx < normalised_contours.size(); contour_idx++) { // For each type of traffic sign /* * sign_type = 0 -> nb_edges = 3; gielis_sym = 6; radius * sign_type = 1 -> nb_edges = 4; gielis_sym = 4; radius * sign_type = 2 -> nb_edges = 12; gielis_sym = 4; radius * sign_type = 3 -> nb_edges = 8; gielis_sym = 8; radius * sign_type = 4 -> nb_edges = 3; gielis_sym = 6; radius / 2 */ Timer tmrSgnType("For signType"); optimisation::ConfigStruct_<double> final_config; double best_fit = std::numeric_limits<double>::infinity(); //int type_sign_to_keep = 0; for (int sign_type = 0; sign_type < 5; sign_type++) { Timer tmrIteration(" for_signType_iter"); // Check the center mass for a contour cv::Point2f mass_center = initopt::mass_center_discovery(input_image, translation_matrix[contour_idx], rotation_matrix[contour_idx], scaling_matrix[contour_idx], normalised_contours[contour_idx], factor_vector[contour_idx], sign_type); // Find the rotation offset double rot_offset = initopt::rotation_offset(normalised_contours[contour_idx]); // Declaration of the parameters of the gielis with the default parameters optimisation::ConfigStruct_<double> contour_config; // Set the number of symmetry int gielis_symmetry = 0; switch (sign_type) { case 0: gielis_symmetry = 6; break; case 1: gielis_symmetry = 4; break; case 2: gielis_symmetry = 4; break; case 3: gielis_symmetry = 8; break; case 4: gielis_symmetry = 6; break; } contour_config.p = gielis_symmetry; // Set the rotation matrix contour_config.theta_offset = rot_offset; // Set the mass center contour_config.x_offset = mass_center.x; contour_config.y_offset = mass_center.y; Timer tmrOpt("\t for_signType_gielisOptimization"); // Go for the optimisation Eigen::Vector4d mean_err(0,0,0,0), std_err(0,0,0,0); optimisation::gielis_optimisation(normalised_contours[contour_idx], contour_config, mean_err, std_err); mean_err = mean_err.cwiseAbs(); double err_fit = mean_err.sum(); if (err_fit < best_fit) { best_fit = err_fit; final_config = contour_config; //type_sign_to_keep = sign_type; } } Timer tmr2("Reconstruct contour"); // Reconstruct the contour std::cout << "Contour #" << contour_idx << ":\n" << final_config << std::endl; std::vector< cv::Point2f > gielis_contour; int nb_points = 1000; optimisation::gielis_reconstruction(final_config, gielis_contour, nb_points); std::vector< cv::Point2f > denormalised_gielis_contour; initopt::denormalise_contour(gielis_contour, denormalised_gielis_contour, factor_vector[contour_idx]); std::vector< cv::Point2f > distorted_gielis_contour; imageprocessing::inverse_transformation_contour(denormalised_gielis_contour, distorted_gielis_contour, translation_matrix[contour_idx], rotation_matrix[contour_idx], scaling_matrix[contour_idx]); // Transform to cv::Point to show the results std::vector< cv::Point > distorted_gielis_contour_int(distorted_gielis_contour.size()); for (unsigned int i = 0; i < distorted_gielis_contour.size(); i++) { distorted_gielis_contour_int[i].x = (int) std::round(distorted_gielis_contour[i].x); distorted_gielis_contour_int[i].y = (int) std::round(distorted_gielis_contour[i].y); } detected_signs_2f[contour_idx] = distorted_gielis_contour; detected_signs[contour_idx] = distorted_gielis_contour_int; } end = std::chrono::system_clock::now(); std::chrono::duration<double> elapsed_seconds = end-start; std::time_t end_time = std::chrono::system_clock::to_time_t(end); std::cout << "Finished computation at " << std::ctime(&end_time) << "Elapsed time: " << elapsed_seconds.count()*1000 << " ms\n"; cv::Mat output_image = input_image.clone(); cv::Scalar color(0,255,0); cv::drawContours(output_image, detected_signs, -1, color, 2, 8); cv::namedWindow("Window", CV_WINDOW_AUTOSIZE); cv::imshow("Window", output_image); cv::waitKey(0); return 0; }
#include "cmm/cmm.h" const mtr_t g_mtr = scaling_matrix(g_factor, g_factor);