/** * Apply Fast Template Matching algorithm */ vector<Point2f> FAsTMatch::apply(Mat& original_image, Mat& original_template ) { /* Preprocess the image and template first */ image = preprocessImage( original_image ); templ = preprocessImage( original_template ); int r1x = 0.5 * (templ.cols - 1), r1y = 0.5 * (templ.rows - 1), r2x = 0.5 * (image.cols - 1), r2y = 0.5 * (image.rows - 1); float min_trans_x = -(r2x - r1x * minScale), max_trans_x = -min_trans_x, min_trans_y = -(r2y - r1y * minScale), max_trans_y = -min_trans_y, min_rotation = -M_PI, max_rotation = M_PI; /* Create the matching grid / net */ MatchNet net( templ.cols, templ.rows, delta, min_trans_x, max_trans_x, min_trans_y, max_trans_y, min_rotation, max_rotation, minScale, maxScale ); /* Smooth our images */ GaussianBlur( templ, templ, Size(0, 0), 2.0, 2.0 ); GaussianBlur( image, image, Size(0, 0), 2.0, 2.0 ); int no_of_points = round( 10 / (epsilon * epsilon) ); /* Randomly sample points */ Mat xs( 1, no_of_points, CV_32SC1 ), ys( 1, no_of_points, CV_32SC1 ); rng.fill( xs, RNG::UNIFORM, 1, templ.cols ); rng.fill( ys, RNG::UNIFORM, 1, templ.rows ); int level = 0; float delta_fact = 1.511f; float new_delta = delta; MatchConfig best_config; Mat best_trans; vector<double> best_distances(20, 0.0); double best_distance; vector<double> distances; vector<bool> insiders; while( true ) { level++; /* First create configurations based on our net */ vector<MatchConfig> configs = createListOfConfigs( net, templ.size(), image.size() ); int configs_count = static_cast<int>(configs.size()); /* Convert the configurations into affine matrices */ vector<Mat> affines = configsToAffine( configs, insiders ); /* Filter out configurations that fall outside of the boundaries */ /* the internal logic of configsToAffine has more information */ vector<MatchConfig> temp_configs; for( int i = 0; i < insiders.size(); i++ ) if( insiders[i] == true ) temp_configs.push_back( configs[i] ); configs = temp_configs; /* For the configs, calculate the scores / distances */ distances = evaluateConfigs( image, templ, affines, xs, ys, photometricInvariance ); /* Find the minimum distance */ auto min_itr = min_element( distances.begin(), distances.end() ); int min_index = static_cast<int>(min_itr - distances.begin()); best_distance = distances[min_index]; best_distances[level] = best_distance; best_config = configs[min_index]; best_trans = best_config.getAffineMatrix(); /* Conditions to exit the loop */ if( (best_distance < 0.005) || ((level > 2) && (best_distance < 0.015)) || level >= 20 ) break; if( level > 3 ) { float mean_value = std::accumulate( best_distances.begin() + level - 3, best_distances.begin() + level - 1, 0 ) * 1.0 / distances.size(); if( best_distance > mean_value * 0.97 ) break; } float thresh; bool too_high_percentage; /* Get the good configurations that falls between certain thresholds */ vector<MatchConfig> good_configs = getGoodConfigsByDistance( configs, best_distance, new_delta, distances, thresh, too_high_percentage ); if ((too_high_percentage && (best_distance > 0.05) && ((level==1) && (configs_count < 7.5e6)) ) || ((best_distance > 0.1) && ((level==1) && (configs_count < 5e6)) ) ) { static float factor = 0.9; new_delta = new_delta * factor; level = 0; net = net * factor; configs = createListOfConfigs( net, templ.size(), image.size() ); } else { new_delta = new_delta / delta_fact; vector<MatchConfig> expanded_configs = randomExpandConfigs( good_configs, net, level, 80, delta_fact ); configs.clear(); configs.insert( configs.end(), good_configs.begin(), good_configs.end() ); configs.insert( configs.end(), expanded_configs.begin(), expanded_configs.end() ); } /* Randomly sample points again */ rng.fill( xs, RNG::UNIFORM, 1, templ.cols ); rng.fill( ys, RNG::UNIFORM, 1, templ.rows ); } /* Return the rectangle corners based on the best affine transformation */ return calcCorners( image.size(), templ.size(), best_trans ); }
cv::Mat SimulatingImage::projectPlane(int pattern) { cv::Mat img = cv::Mat::zeros(img_size.height, img_size.width, CV_8UC1); calcCorners(); for (int y = 0; y < img_size.height; ++y) { for (int x = 0; x < img_size.width; ++x) { cv::Point3d ray = getRay(cv::Point2d(x,y)); if (isCross(ray)) { cv::Point3d p = calcCrossPoint(ray); double s = calcS(p); double t = calcT(p); if (0 <= s && s <= 1 && 0 <= t && t <= 1) { double step; switch (pattern) { case 0: // check step = interval / pattern_size.width; for (int i = 0; 2*i*step <= 1.0; ++i) { if (step*(2*i) <= s && s <= step*(2*i+1)) { img.at<uchar>(y,x) = 255; break; } } step = interval / pattern_size.height; for (int i = 0; 2*i*step <= 1.0; ++i) { if (step*(2*i) <= t && t <= step*(2*i+1)) { img.at<uchar>(y,x) = abs(img.at<uchar>(y,x)-255); break; } } break; case 1: // vertical strip step = interval / pattern_size.width; for (int i = 0; 2*i*step <= 1.0; ++i) { if (step*(2*i) <= s && s <= step*(2*i+1)) { img.at<uchar>(y,x) = 255; break; } } break; case 2: // inverse of 1 step = interval / pattern_size.width; for (int i = 0; (2*i+1)*step <= 1.0; ++i) { if (step*(2*i+1) <= s && s <= step*(2*i+2)) { img.at<uchar>(y,x) = 255; break; } } break; case 3: // horizontal strip step = interval / pattern_size.height; for (int i = 0; 2*i*step <= 1.0; ++i) { if (step*(2*i) <= t && t <= step*(2*i+1)) { img.at<uchar>(y,x) = 255; break; } } break; case 4: // inverse of 3 step = interval / pattern_size.height; for (int i = 0; (2*i+1)*step <= 1.0; ++i) { if (step*(2*i+1) <= t && t <= step*(2*i+2)) { img.at<uchar>(y,x) = 255; break; } } break; } } } } } return img; }