Advertisement
Guest User

chamfermatching2.cpp

a guest
Aug 12th, 2014
907
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 43.08 KB | None | 0 0
  1. /*********************************************************************
  2.  * Software License Agreement (BSD License)
  3.  *
  4.  *  Copyright (c) 2008-2010, Willow Garage, Inc.
  5.  *  All rights reserved.
  6.  *
  7.  *  Redistribution and use in source and binary forms, with or without
  8.  *  modification, are permitted provided that the following conditions
  9.  *  are met:
  10.  *
  11.  *   * Redistributions of source code must retain the above copyright
  12.  *     notice, this list of conditions and the following disclaimer.
  13.  *   * Redistributions in binary form must reproduce the above
  14.  *     copyright notice, this list of conditions and the following
  15.  *     disclaimer in the documentation and/or other materials provided
  16.  *     with the distribution.
  17.  *   * Neither the name of the Willow Garage nor the names of its
  18.  *     contributors may be used to endorse or promote products derived
  19.  *     from this software without specific prior written permission.
  20.  *
  21.  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22.  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23.  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24.  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25.  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26.  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27.  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28.  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29.  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31.  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32.  *  POSSIBILITY OF SUCH DAMAGE.
  33.  *********************************************************************/
  34.  
  35. //
  36. // The original code was written by
  37. //          Marius Muja
  38. // and later modified and prepared
  39. //  for integration into OpenCV by
  40. //        Antonella Cascitelli,
  41. //        Marco Di Stefano and
  42. //          Stefano Fabri
  43. //        from Univ. of Rome
  44. //
  45. #include "stdafx.h"
  46. //#include "precomp.hpp"
  47. #include "imgproc.hpp"
  48. #include "opencv2/opencv_modules.hpp"
  49. #ifdef HAVE_OPENCV_HIGHGUI
  50. #  include "opencv2/highgui/highgui.hpp"
  51. #endif
  52. #include <iostream>
  53. #include <queue>
  54.  
  55. namespace cv
  56. {
  57.  
  58. using std::queue;
  59.  
  60. typedef std::pair<int,int> coordinate_t;
  61. typedef float orientation_t;
  62. typedef std::vector<coordinate_t> template_coords_t;
  63. typedef std::vector<orientation_t> template_orientations_t;
  64. typedef std::pair<Point, float> location_scale_t;
  65.  
  66. class ChamferMatcher
  67. {
  68.  
  69. private:
  70.     class Matching;
  71.     int max_matches_;
  72.     float min_match_distance_;
  73.  
  74.     ///////////////////////// Image iterators ////////////////////////////
  75.  
  76.     class ImageIterator
  77.     {
  78.     public:
  79.         virtual ~ImageIterator() {}
  80.         virtual bool hasNext() const = 0;
  81.         virtual location_scale_t next() = 0;
  82.     };
  83.  
  84.     class ImageRange
  85.     {
  86.     public:
  87.         virtual ImageIterator* iterator() const = 0;
  88.         virtual ~ImageRange() {}
  89.     };
  90.  
  91.     // Sliding window
  92.  
  93.     class SlidingWindowImageRange : public ImageRange
  94.     {
  95.         int width_;
  96.         int height_;
  97.         int x_step_;
  98.         int y_step_;
  99.         int scales_;
  100.         float min_scale_;
  101.         float max_scale_;
  102.  
  103.     public:
  104.         SlidingWindowImageRange(int width, int height, int x_step = 3, int y_step = 3, int _scales = 5, float min_scale = 0.6, float max_scale = 1.6) :
  105.         width_(width), height_(height), x_step_(x_step),y_step_(y_step), scales_(_scales), min_scale_(min_scale), max_scale_(max_scale)
  106.         {
  107.         }
  108.  
  109.  
  110.         ImageIterator* iterator() const;
  111.     };
  112.  
  113.     class LocationImageRange : public ImageRange
  114.     {
  115.         const std::vector<Point>& locations_;
  116.  
  117.         int scales_;
  118.         float min_scale_;
  119.         float max_scale_;
  120.  
  121.         LocationImageRange(const LocationImageRange&);
  122.         LocationImageRange& operator=(const LocationImageRange&);
  123.  
  124.     public:
  125.         LocationImageRange(const std::vector<Point>& locations, int _scales = 5, float min_scale = 0.6, float max_scale = 1.6) :
  126.         locations_(locations), scales_(_scales), min_scale_(min_scale), max_scale_(max_scale)
  127.         {
  128.         }
  129.  
  130.         ImageIterator* iterator() const
  131.         {
  132.             return new LocationImageIterator(locations_, scales_, min_scale_, max_scale_);
  133.         }
  134.     };
  135.  
  136.  
  137.     class LocationScaleImageRange : public ImageRange
  138.     {
  139.         const std::vector<Point>& locations_;
  140.         const std::vector<float>& scales_;
  141.  
  142.         LocationScaleImageRange(const LocationScaleImageRange&);
  143.         LocationScaleImageRange& operator=(const LocationScaleImageRange&);
  144.     public:
  145.         LocationScaleImageRange(const std::vector<Point>& locations, const std::vector<float>& _scales) :
  146.         locations_(locations), scales_(_scales)
  147.         {
  148.             assert(locations.size()==_scales.size());
  149.         }
  150.  
  151.         ImageIterator* iterator() const
  152.         {
  153.             return new LocationScaleImageIterator(locations_, scales_);
  154.         }
  155.     };
  156.  
  157.  
  158.  
  159.  
  160. public:
  161.     /**
  162.      * Class that represents a template for chamfer matching.
  163.      */
  164.     class Template
  165.     {
  166.         friend class ChamferMatcher::Matching;
  167.         friend class ChamferMatcher;
  168.  
  169.  
  170.     public:
  171.         std::vector<Template*> scaled_templates;
  172.         std::vector<int> addr;
  173.         int addr_width;
  174.         float scale;
  175.         template_coords_t coords;
  176.  
  177.         template_orientations_t orientations;
  178.         Size size;
  179.         Point center;
  180.  
  181.     public:
  182.         Template() : addr_width(-1)
  183.         {
  184.         }
  185.  
  186.         Template(Mat& edge_image, float scale_ = 1);
  187.  
  188.         ~Template()
  189.         {
  190.             for (size_t i=0;i<scaled_templates.size();++i) {
  191.                 delete scaled_templates[i];
  192.             }
  193.             scaled_templates.clear();
  194.             coords.clear();
  195.             orientations.clear();
  196.         }
  197.         void show() const;
  198.  
  199.  
  200.  
  201.     private:
  202.         /**
  203.          * Resizes a template
  204.          *
  205.          * @param scale Scale to be resized to
  206.          */
  207.         Template* rescale(float scale);
  208.  
  209.         std::vector<int>& getTemplateAddresses(int width);
  210.     };
  211.  
  212.  
  213.  
  214.     /**
  215.      * Used to represent a matching result.
  216.      */
  217.  
  218.     class Match
  219.     {
  220.     public:
  221.         float cost;
  222.         Point offset;
  223.         const Template* tpl;
  224.     };
  225.  
  226.     typedef std::vector<Match> Matches;
  227.  
  228. private:
  229.     /**
  230.      * Implements the chamfer matching algorithm on images taking into account both distance from
  231.      * the template pixels to the nearest pixels and orientation alignment between template and image
  232.      * contours.
  233.      */
  234.     class Matching
  235.     {
  236.         float truncate_;
  237.         bool use_orientation_;
  238.  
  239.         std::vector<Template*> templates;
  240.     public:
  241.         Matching(bool use_orientation = true, float _truncate = 10) : truncate_(_truncate), use_orientation_(use_orientation)
  242.         {
  243.         }
  244.  
  245.         ~Matching()
  246.         {
  247.             for (size_t i = 0; i<templates.size(); i++) {
  248.                 //delete templates[i];
  249.             }
  250.         }
  251.  
  252.         /**
  253.          * Add a template to the detector from an edge image.
  254.          * @param templ An edge image
  255.          */
  256.         void addTemplateFromImage(Mat& templ, float scale = 1.0);
  257.  
  258.         /**
  259.          * Run matching using an edge image.
  260.          * @param edge_img Edge image
  261.          * @return a match object
  262.          */
  263.         ChamferMatcher::Matches* matchEdgeImage(Mat& edge_img, const ImageRange& range, float orientation_weight = 0.5, int max_matches = 20, float min_match_distance = 10.0);
  264.  
  265.         void addTemplate(Template& template_);
  266.  
  267.     private:
  268.  
  269.         float orientation_diff(float o1, float o2)
  270.         {
  271.             return fabs(o1-o2);
  272.         }
  273.  
  274.         /**
  275.          * Computes the chamfer matching cost for one position in the target image.
  276.          * @param offset Offset where to compute cost
  277.          * @param dist_img Distance transform image.
  278.          * @param orientation_img Orientation image.
  279.          * @param tpl Template
  280.          * @param templ_orientations Orientations of the target points.
  281.          * @return matching result
  282.          */
  283.         ChamferMatcher::Match* localChamferDistance(Point offset, Mat& dist_img, Mat& orientation_img, Template* tpl,  float orientation_weight);
  284.  
  285.     private:
  286.         /**
  287.          * Matches all templates.
  288.          * @param dist_img Distance transform image.
  289.          * @param orientation_img Orientation image.
  290.          */
  291.         ChamferMatcher::Matches* matchTemplates(Mat& dist_img, Mat& orientation_img, const ImageRange& range, float orientation_weight);
  292.  
  293.         void computeDistanceTransform(Mat& edges_img, Mat& dist_img, Mat& annotate_img, float truncate_dt, float a, float b);
  294.         void computeEdgeOrientations(Mat& edge_img, Mat& orientation_img);
  295.         void fillNonContourOrientations(Mat& annotated_img, Mat& orientation_img);
  296.  
  297.  
  298.     public:
  299.         /**
  300.          * Finds a contour in an edge image. The original image is altered by removing the found contour.
  301.          * @param templ_img Edge image
  302.          * @param coords Coordinates forming the contour.
  303.          * @return True while a contour is still found in the image.
  304.          */
  305.         static bool findContour(Mat& templ_img, template_coords_t& coords);
  306.  
  307.         /**
  308.          * Computes contour points orientations using the approach from:
  309.          *
  310.          * Matas, Shao and Kittler - Estimation of Curvature and Tangent Direction by
  311.          * Median Filtered Differencing
  312.          *
  313.          * @param coords Contour points
  314.          * @param orientations Contour points orientations
  315.          */
  316.         static void findContourOrientations(const template_coords_t& coords, template_orientations_t& orientations);
  317.  
  318.  
  319.         /**
  320.          * Computes the angle of a line segment.
  321.          *
  322.          * @param a One end of the line segment
  323.          * @param b The other end.
  324.          * @param dx
  325.          * @param dy
  326.          * @return Angle in radians.
  327.          */
  328.         static float getAngle(coordinate_t a, coordinate_t b, int& dx, int& dy);
  329.  
  330.         /**
  331.          * Finds a point in the image from which to start contour following.
  332.          * @param templ_img
  333.          * @param p
  334.          * @return
  335.          */
  336.  
  337.         static bool findFirstContourPoint(Mat& templ_img, coordinate_t& p);
  338.         /**
  339.          * Method that extracts a single continuous contour from an image given a starting point.
  340.          * When it extracts the contour it tries to maintain the same direction (at a T-join for example).
  341.          *
  342.          * @param templ_
  343.          * @param coords
  344.          * @param direction
  345.          */
  346.         static void followContour(Mat& templ_img, template_coords_t& coords, int direction);
  347.  
  348.  
  349.     };
  350.  
  351.  
  352.  
  353.  
  354.     class LocationImageIterator : public ImageIterator
  355.     {
  356.         const std::vector<Point>& locations_;
  357.  
  358.         size_t iter_;
  359.  
  360.         int scales_;
  361.         float min_scale_;
  362.         float max_scale_;
  363.  
  364.         float scale_;
  365.         float scale_step_;
  366.         int scale_cnt_;
  367.  
  368.         bool has_next_;
  369.  
  370.         LocationImageIterator(const LocationImageIterator&);
  371.         LocationImageIterator& operator=(const LocationImageIterator&);
  372.  
  373.     public:
  374.         LocationImageIterator(const std::vector<Point>& locations, int _scales, float min_scale, float max_scale);
  375.  
  376.         bool hasNext() const {
  377.             return has_next_;
  378.         }
  379.  
  380.         location_scale_t next();
  381.     };
  382.  
  383.     class LocationScaleImageIterator : public ImageIterator
  384.     {
  385.         const std::vector<Point>& locations_;
  386.         const std::vector<float>& scales_;
  387.  
  388.         size_t iter_;
  389.  
  390.         bool has_next_;
  391.  
  392.         LocationScaleImageIterator(const LocationScaleImageIterator&);
  393.         LocationScaleImageIterator& operator=(const LocationScaleImageIterator&);
  394.  
  395.     public:
  396.         LocationScaleImageIterator(const std::vector<Point>& locations, const std::vector<float>& _scales) :
  397.         locations_(locations), scales_(_scales)
  398.         {
  399.             assert(locations.size()==_scales.size());
  400.             reset();
  401.         }
  402.  
  403.         void reset()
  404.         {
  405.             iter_ = 0;
  406.             has_next_ = (locations_.size()==0 ? false : true);
  407.         }
  408.  
  409.         bool hasNext() const {
  410.             return has_next_;
  411.         }
  412.  
  413.         location_scale_t next();
  414.     };
  415.  
  416.     class SlidingWindowImageIterator : public ImageIterator
  417.     {
  418.         int x_;
  419.         int y_;
  420.         float scale_;
  421.         float scale_step_;
  422.         int scale_cnt_;
  423.  
  424.         bool has_next_;
  425.  
  426.         int width_;
  427.         int height_;
  428.         int x_step_;
  429.         int y_step_;
  430.         int scales_;
  431.         float min_scale_;
  432.         float max_scale_;
  433.  
  434.  
  435.     public:
  436.  
  437.         SlidingWindowImageIterator(int width, int height, int x_step, int y_step, int scales, float min_scale, float max_scale);
  438.  
  439.         bool hasNext() const {
  440.             return has_next_;
  441.         }
  442.  
  443.         location_scale_t next();
  444.     };
  445.  
  446.  
  447.  
  448.  
  449.     int count;
  450.     Matches matches;
  451.     int pad_x;
  452.     int pad_y;
  453.     int scales;
  454.     float minScale;
  455.     float maxScale;
  456.     float orientation_weight;
  457.     float truncate;
  458.     Matching * chamfer_;
  459.  
  460. public:
  461.     ChamferMatcher(int _max_matches = 20, float _min_match_distance = 1.0, int _pad_x = 3,
  462.                    int _pad_y = 3, int _scales = 5, float _minScale = 0.6, float _maxScale = 1.6,
  463.                    float _orientation_weight = 0.5, float _truncate = 20)
  464.     {
  465.         max_matches_ = _max_matches;
  466.         min_match_distance_ = _min_match_distance;
  467.         pad_x = _pad_x;
  468.         pad_y = _pad_y;
  469.         scales = _scales;
  470.         minScale = _minScale;
  471.         maxScale = _maxScale;
  472.         orientation_weight = _orientation_weight;
  473.         truncate = _truncate;
  474.         count = 0;
  475.  
  476.         matches.resize(max_matches_);
  477.         chamfer_ = new Matching(true);
  478.     }
  479.  
  480.     ~ChamferMatcher()
  481.     {
  482.         delete chamfer_;
  483.     }
  484.  
  485.     void showMatch(Mat& img, int index = 0);
  486.     void showMatch(Mat& img, Match match_);
  487.  
  488.     const Matches& matching(Template&, Mat&);
  489.  
  490. private:
  491.     ChamferMatcher(const ChamferMatcher&);
  492.     ChamferMatcher& operator=(const ChamferMatcher&);
  493.     void addMatch(float cost, Point offset, const Template* tpl);
  494.  
  495.  
  496. };
  497.  
  498.  
  499. ///////////////////// implementation ///////////////////////////
  500.  
  501. ChamferMatcher::SlidingWindowImageIterator::SlidingWindowImageIterator( int width,
  502.                                                                         int height,
  503.                                                                         int x_step = 3,
  504.                                                                         int y_step = 3,
  505.                                                                         int _scales = 5,
  506.                                                                         float min_scale = 0.6,
  507.                                                                         float max_scale = 1.6) :
  508.  
  509.                                                                             width_(width),
  510.                                                                             height_(height),
  511.                                                                             x_step_(x_step),
  512.                                                                             y_step_(y_step),
  513.                                                                             scales_(_scales),
  514.                                                                             min_scale_(min_scale),
  515.                                                                             max_scale_(max_scale)
  516. {
  517.     x_ = 0;
  518.     y_ = 0;
  519.     scale_cnt_ = 0;
  520.     scale_ = min_scale_;
  521.     has_next_ = true;
  522.     scale_step_ = (max_scale_-min_scale_)/scales_;
  523. }
  524.  
  525. location_scale_t ChamferMatcher::SlidingWindowImageIterator::next()
  526. {
  527.     location_scale_t next_val = std::make_pair(Point(x_,y_),scale_);
  528.  
  529.     x_ += x_step_;
  530.  
  531.     if (x_ >= width_) {
  532.         x_ = 0;
  533.         y_ += y_step_;
  534.  
  535.         if (y_ >= height_) {
  536.             y_ = 0;
  537.             scale_ += scale_step_;
  538.             scale_cnt_++;
  539.  
  540.             if (scale_cnt_ == scales_) {
  541.                 has_next_ = false;
  542.                 scale_cnt_ = 0;
  543.                 scale_ = min_scale_;
  544.             }
  545.         }
  546.     }
  547.  
  548.     return next_val;
  549. }
  550.  
  551.  
  552.  
  553. ChamferMatcher::ImageIterator* ChamferMatcher::SlidingWindowImageRange::iterator() const
  554. {
  555.     return new SlidingWindowImageIterator(width_, height_, x_step_, y_step_, scales_, min_scale_, max_scale_);
  556. }
  557.  
  558.  
  559.  
  560. ChamferMatcher::LocationImageIterator::LocationImageIterator(const std::vector<Point>& locations,
  561.                                                                 int _scales = 5,
  562.                                                                 float min_scale = 0.6,
  563.                                                                 float max_scale = 1.6) :
  564.                                                                     locations_(locations),
  565.                                                                     scales_(_scales),
  566.                                                                     min_scale_(min_scale),
  567.                                                                     max_scale_(max_scale)
  568. {
  569.     iter_ = 0;
  570.     scale_cnt_ = 0;
  571.     scale_ = min_scale_;
  572.     has_next_ = (locations_.size()==0 ? false : true);
  573.     scale_step_ = (max_scale_-min_scale_)/scales_;
  574. }
  575.  
  576. location_scale_t ChamferMatcher::LocationImageIterator:: next()
  577. {
  578.     location_scale_t next_val = std::make_pair(locations_[iter_],scale_);
  579.  
  580.     iter_ ++;
  581.     if (iter_==locations_.size()) {
  582.         iter_ = 0;
  583.         scale_ += scale_step_;
  584.         scale_cnt_++;
  585.  
  586.         if (scale_cnt_ == scales_) {
  587.             has_next_ = false;
  588.             scale_cnt_ = 0;
  589.             scale_ = min_scale_;
  590.         }
  591.     }
  592.  
  593.     return next_val;
  594. }
  595.  
  596.  
  597. location_scale_t ChamferMatcher::LocationScaleImageIterator::next()
  598. {
  599.     location_scale_t next_val = std::make_pair(locations_[iter_],scales_[iter_]);
  600.  
  601.     iter_ ++;
  602.     if (iter_==locations_.size()) {
  603.         iter_ = 0;
  604.  
  605.         has_next_ = false;
  606.     }
  607.  
  608.     return next_val;
  609. }
  610.  
  611.  
  612.  
  613. bool ChamferMatcher::Matching::findFirstContourPoint(Mat& templ_img, coordinate_t& p)
  614. {
  615.     for (int y=0;y<templ_img.rows;++y) {
  616.         for (int x=0;x<templ_img.cols;++x) {
  617.             if (templ_img.at<uchar>(y,x)!=0) {
  618.                 p.first = x;
  619.                 p.second = y;
  620.                 return true;
  621.             }
  622.         }
  623.     }
  624.     return false;
  625. }
  626.  
  627.  
  628.  
  629. void ChamferMatcher::Matching::followContour(Mat& templ_img, template_coords_t& coords, int direction = -1)
  630. {
  631.     const int dir[][2] = { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} };
  632.     coordinate_t next;
  633.     unsigned char ptr;
  634.  
  635.     assert (direction==-1 || !coords.empty());
  636.  
  637.     coordinate_t crt = coords.back();
  638.  
  639.     // mark the current pixel as visited
  640.     templ_img.at<uchar>(crt.second,crt.first) = 0;
  641.     if (direction==-1) {
  642.         for (int j = 0; j<7; ++j) {
  643.             next.first = crt.first + dir[j][1];
  644.             next.second = crt.second + dir[j][0];
  645.             if (next.first >= 0 && next.first < templ_img.cols &&
  646.                 next.second >= 0 && next.second < templ_img.rows){
  647.                 ptr = templ_img.at<uchar>(next.second, next.first);
  648.                 if (ptr!=0) {
  649.                     coords.push_back(next);
  650.                     followContour(templ_img, coords,j);
  651.                     // try to continue contour in the other direction
  652.                     reverse(coords.begin(), coords.end());
  653.                     followContour(templ_img, coords, (j+4)%8);
  654.                     break;
  655.                 }
  656.             }
  657.         }
  658.     }
  659.     else {
  660.         int k = direction;
  661.         int k_cost = 3;
  662.         next.first = crt.first + dir[k][1];
  663.         next.second = crt.second + dir[k][0];
  664.         if (next.first >= 0 && next.first < templ_img.cols &&
  665.                 next.second >= 0 && next.second < templ_img.rows){
  666.             ptr = templ_img.at<uchar>(next.second, next.first);
  667.             if (ptr!=0) {
  668.                 k_cost = std::abs(dir[k][1]) + std::abs(dir[k][0]);
  669.             }
  670.             int p = k;
  671.             int n = k;
  672.  
  673.             for (int j = 0 ;j<3; ++j) {
  674.                 p = (p + 7) % 8;
  675.                 n = (n + 1) % 8;
  676.                 next.first = crt.first + dir[p][1];
  677.                 next.second = crt.second + dir[p][0];
  678.                 if (next.first >= 0 && next.first < templ_img.cols &&
  679.                     next.second >= 0 && next.second < templ_img.rows){
  680.                     ptr = templ_img.at<uchar>(next.second, next.first);
  681.                     if (ptr!=0) {
  682.                         int p_cost = std::abs(dir[p][1]) + std::abs(dir[p][0]);
  683.                         if (p_cost<k_cost) {
  684.                             k_cost = p_cost;
  685.                             k = p;
  686.                         }
  687.                     }
  688.                     next.first = crt.first + dir[n][1];
  689.                     next.second = crt.second + dir[n][0];
  690.                     if (next.first >= 0 && next.first < templ_img.cols &&
  691.                     next.second >= 0 && next.second < templ_img.rows){
  692.                         ptr = templ_img.at<uchar>(next.second, next.first);
  693.                         if (ptr!=0) {
  694.                             int n_cost = std::abs(dir[n][1]) + std::abs(dir[n][0]);
  695.                             if (n_cost<k_cost) {
  696.                                 k_cost = n_cost;
  697.                                 k = n;
  698.                             }
  699.                         }
  700.                     }
  701.                 }
  702.             }
  703.  
  704.             if (k_cost!=3) {
  705.                 next.first = crt.first + dir[k][1];
  706.                 next.second = crt.second + dir[k][0];
  707.                 if (next.first >= 0 && next.first < templ_img.cols &&
  708.                     next.second >= 0 && next.second < templ_img.rows) {
  709.                     coords.push_back(next);
  710.                     followContour(templ_img, coords, k);
  711.                 }
  712.             }
  713.         }
  714.     }
  715. }
  716.  
  717.  
  718. bool ChamferMatcher::Matching::findContour(Mat& templ_img, template_coords_t& coords)
  719. {
  720.     coordinate_t start_point;
  721.  
  722.     bool found = findFirstContourPoint(templ_img,start_point);
  723.     if (found) {
  724.         coords.push_back(start_point);
  725.         followContour(templ_img, coords);
  726.         return true;
  727.     }
  728.  
  729.     return false;
  730. }
  731.  
  732.  
  733. float ChamferMatcher::Matching::getAngle(coordinate_t a, coordinate_t b, int& dx, int& dy)
  734. {
  735.     dx = b.first-a.first;
  736.     dy = -(b.second-a.second);  // in image coordinated Y axis points downward
  737.         float angle = atan2((float)dy,(float)dx);
  738.  
  739.     if (angle<0) {
  740.                 angle+=(float)CV_PI;
  741.     }
  742.  
  743.     return angle;
  744. }
  745.  
  746.  
  747.  
  748. void ChamferMatcher::Matching::findContourOrientations(const template_coords_t& coords, template_orientations_t& orientations)
  749. {
  750.     const int M = 5;
  751.     int coords_size = (int)coords.size();
  752.  
  753.     std::vector<float> angles(2*M);
  754.         orientations.insert(orientations.begin(), coords_size, float(-3*CV_PI)); // mark as invalid in the beginning
  755.  
  756.     if (coords_size<2*M+1) {  // if contour not long enough to estimate orientations, abort
  757.         return;
  758.     }
  759.  
  760.     for (int i=M;i<coords_size-M;++i) {
  761.         coordinate_t crt = coords[i];
  762.         coordinate_t other;
  763.         int k = 0;
  764.         int dx, dy;
  765.         // compute previous M angles
  766.         for (int j=M;j>0;--j) {
  767.             other = coords[i-j];
  768.             angles[k++] = getAngle(other,crt, dx, dy);
  769.         }
  770.         // compute next M angles
  771.         for (int j=1;j<=M;++j) {
  772.             other = coords[i+j];
  773.             angles[k++] = getAngle(crt, other, dx, dy);
  774.         }
  775.  
  776.         // get the middle two angles
  777.         std::nth_element(angles.begin(), angles.begin()+M-1,  angles.end());
  778.         std::nth_element(angles.begin()+M-1, angles.begin()+M,  angles.end());
  779.         //        sort(angles.begin(), angles.end());
  780.  
  781.         // average them to compute tangent
  782.         orientations[i] = (angles[M-1]+angles[M])/2;
  783.     }
  784. }
  785.  
  786. //////////////////////// Template /////////////////////////////////////
  787.  
  788. ChamferMatcher::Template::Template(Mat& edge_image, float scale_) : addr_width(-1), scale(scale_)
  789. {
  790.     template_coords_t local_coords;
  791.     template_orientations_t local_orientations;
  792.  
  793.     while (ChamferMatcher::Matching::findContour(edge_image, local_coords)) {
  794.         ChamferMatcher::Matching::findContourOrientations(local_coords, local_orientations);
  795.  
  796.         coords.insert(coords.end(), local_coords.begin(), local_coords.end());
  797.         orientations.insert(orientations.end(), local_orientations.begin(), local_orientations.end());
  798.         local_coords.clear();
  799.         local_orientations.clear();
  800.     }
  801.  
  802.  
  803.     size = edge_image.size();
  804.     Point min, max;
  805.     min.x = size.width;
  806.     min.y = size.height;
  807.     max.x = 0;
  808.     max.y = 0;
  809.  
  810.     center = Point(0,0);
  811.     for (size_t i=0;i<coords.size();++i) {
  812.         center.x += coords[i].first;
  813.         center.y += coords[i].second;
  814.  
  815.         if (min.x>coords[i].first) min.x = coords[i].first;
  816.         if (min.y>coords[i].second) min.y = coords[i].second;
  817.         if (max.x<coords[i].first) max.x = coords[i].first;
  818.         if (max.y<coords[i].second) max.y = coords[i].second;
  819.     }
  820.  
  821.     size.width = max.x - min.x;
  822.     size.height = max.y - min.y;
  823.     int coords_size = (int)coords.size();
  824.  
  825.     center.x /= MAX(coords_size, 1);
  826.     center.y /= MAX(coords_size, 1);
  827.  
  828.     for (int i=0;i<coords_size;++i) {
  829.         coords[i].first -= center.x;
  830.         coords[i].second -= center.y;
  831.     }
  832. }
  833.  
  834.  
  835. vector<int>& ChamferMatcher::Template::getTemplateAddresses(int width)
  836. {
  837.     if (addr_width!=width) {
  838.         addr.resize(coords.size());
  839.         addr_width = width;
  840.  
  841.         for (size_t i=0; i<coords.size();++i) {
  842.             addr[i] = coords[i].second*width+coords[i].first;
  843.         }
  844.     }
  845.     return addr;
  846. }
  847.  
  848.  
  849. /**
  850.  * Resizes a template
  851.  *
  852.  * @param scale Scale to be resized to
  853.  */
  854. ChamferMatcher::Template* ChamferMatcher::Template::rescale(float new_scale)
  855. {
  856.  
  857.     if (fabs(scale-new_scale)<1e-6) return this;
  858.  
  859.     for (size_t i=0;i<scaled_templates.size();++i) {
  860.         if (fabs(scaled_templates[i]->scale-new_scale)<1e-6) {
  861.             return scaled_templates[i];
  862.         }
  863.     }
  864.  
  865.     float scale_factor = new_scale/scale;
  866.  
  867.     Template* tpl = new Template();
  868.     tpl->scale = new_scale;
  869.  
  870.     tpl->center.x = int(center.x*scale_factor+0.5);
  871.     tpl->center.y = int(center.y*scale_factor+0.5);
  872.  
  873.     tpl->size.width = int(size.width*scale_factor+0.5);
  874.     tpl->size.height = int(size.height*scale_factor+0.5);
  875.  
  876.     tpl->coords.resize(coords.size());
  877.     tpl->orientations.resize(orientations.size());
  878.     for (size_t i=0;i<coords.size();++i) {
  879.         tpl->coords[i].first = int(coords[i].first*scale_factor+0.5);
  880.         tpl->coords[i].second = int(coords[i].second*scale_factor+0.5);
  881.         tpl->orientations[i] = orientations[i];
  882.     }
  883.     scaled_templates.push_back(tpl);
  884.  
  885.     return tpl;
  886.  
  887. }
  888.  
  889.  
  890.  
  891. void ChamferMatcher::Template::show() const
  892. {
  893.     int pad = 50;
  894.     //Attention size is not correct
  895.     Mat templ_color (Size(size.width+(pad*2), size.height+(pad*2)), CV_8UC3);
  896.     templ_color.setTo(0);
  897.  
  898.     for (size_t i=0;i<coords.size();++i) {
  899.  
  900.         int x = center.x+coords[i].first+pad;
  901.         int y = center.y+coords[i].second+pad;
  902.         templ_color.at<Vec3b>(y,x)[1]=255;
  903.         //CV_PIXEL(unsigned char, templ_color,x,y)[1] = 255;
  904.  
  905.         if (i%3==0) {
  906.                         if (orientations[i] < -CV_PI) {
  907.                 continue;
  908.             }
  909.             Point p1;
  910.             p1.x = x;
  911.             p1.y = y;
  912.             Point p2;
  913.             p2.x = x + pad*(int)(sin(orientations[i])*100)/100;
  914.             p2.y = y + pad*(int)(cos(orientations[i])*100)/100;
  915.  
  916.             line(templ_color, p1,p2, CV_RGB(255,0,0));
  917.         }
  918.     }
  919.  
  920.     circle(templ_color,Point(center.x + pad, center.y + pad),1,CV_RGB(0,255,0));
  921.  
  922. #ifdef HAVE_OPENCV_HIGHGUI
  923.     namedWindow("templ",1);
  924.     imshow("templ",templ_color);
  925.  
  926.     cvWaitKey(0);
  927. #else
  928.     CV_Error(CV_StsNotImplemented, "OpenCV has been compiled without GUI support");
  929. #endif
  930.  
  931.     templ_color.release();
  932. }
  933.  
  934.  
  935. //////////////////////// Matching /////////////////////////////////////
  936.  
  937.  
  938. void ChamferMatcher::Matching::addTemplateFromImage(Mat& templ, float scale)
  939. {
  940.     Template* cmt = new Template(templ, scale);
  941.     templates.clear();
  942.     templates.push_back(cmt);
  943.     cmt->show();
  944. }
  945.  
  946. void ChamferMatcher::Matching::addTemplate(Template& template_){
  947.     templates.clear();
  948.     templates.push_back(&template_);
  949. }
  950. /**
  951.  * Alternative version of computeDistanceTransform, will probably be used to compute distance
  952.  * transform annotated with edge orientation.
  953.  */
  954. void ChamferMatcher::Matching::computeDistanceTransform(Mat& edges_img, Mat& dist_img, Mat& annotate_img, float truncate_dt, float a = 1.0, float b = 1.5)
  955. {
  956.     int d[][2] = { {-1,-1}, { 0,-1}, { 1,-1},
  957.             {-1,0},          { 1,0},
  958.             {-1,1}, { 0,1}, { 1,1} };
  959.  
  960.  
  961.     Size s = edges_img.size();
  962.     int w = s.width;
  963.     int h = s.height;
  964.     // set distance to the edge pixels to 0 and put them in the queue
  965.     std::queue<std::pair<int,int> > q;
  966.  
  967.     for (int y=0;y<h;++y) {
  968.         for (int x=0;x<w;++x) {
  969.             // initialize
  970.             if (&annotate_img!=NULL) {
  971.                 annotate_img.at<Vec2i>(y,x)[0]=x;
  972.                 annotate_img.at<Vec2i>(y,x)[1]=y;
  973.             }
  974.  
  975.             uchar edge_val = edges_img.at<uchar>(y,x);
  976.             if( (edge_val!=0) ) {
  977.                 q.push(std::make_pair(x,y));
  978.                 dist_img.at<float>(y,x)= 0;
  979.             }
  980.             else {
  981.                 dist_img.at<float>(y,x)=-1;
  982.             }
  983.         }
  984.     }
  985.  
  986.     // breadth first computation of distance transform
  987.     std::pair<int,int> crt;
  988.     while (!q.empty()) {
  989.         crt = q.front();
  990.         q.pop();
  991.  
  992.         int x = crt.first;
  993.         int y = crt.second;
  994.  
  995.         float dist_orig = dist_img.at<float>(y,x);
  996.         float dist;
  997.  
  998.         for (size_t i=0;i<sizeof(d)/sizeof(d[0]);++i) {
  999.             int nx = x + d[i][0];
  1000.             int ny = y + d[i][1];
  1001.  
  1002.             if (nx<0 || ny<0 || nx>=w || ny>=h) continue;
  1003.  
  1004.             if (std::abs(d[i][0]+d[i][1])==1) {
  1005.                 dist = (dist_orig)+a;
  1006.             }
  1007.             else {
  1008.                 dist = (dist_orig)+b;
  1009.             }
  1010.  
  1011.             float dt = dist_img.at<float>(ny,nx);
  1012.  
  1013.             if (dt==-1 || dt>dist) {
  1014.                 dist_img.at<float>(ny,nx) = dist;
  1015.                 q.push(std::make_pair(nx,ny));
  1016.  
  1017.                 if (&annotate_img!=NULL) {
  1018.                     annotate_img.at<Vec2i>(ny,nx)[0]=annotate_img.at<Vec2i>(y,x)[0];
  1019.                     annotate_img.at<Vec2i>(ny,nx)[1]=annotate_img.at<Vec2i>(y,x)[1];
  1020.                 }
  1021.             }
  1022.         }
  1023.     }
  1024.     // truncate dt
  1025.  
  1026.     if (truncate_dt>0) {
  1027.         Mat dist_img_thr = dist_img.clone();
  1028.         threshold(dist_img, dist_img_thr, truncate_dt,0.0 ,THRESH_TRUNC);
  1029.         dist_img_thr.copyTo(dist_img);
  1030.     }
  1031. }
  1032.  
  1033.  
  1034. void ChamferMatcher::Matching::computeEdgeOrientations(Mat& edge_img, Mat& orientation_img)
  1035. {
  1036.     Mat contour_img(edge_img.size(), CV_8UC1);
  1037.  
  1038.         orientation_img.setTo(3*(-CV_PI));
  1039.     template_coords_t coords;
  1040.     template_orientations_t orientations;
  1041.  
  1042.     while (ChamferMatcher::Matching::findContour(edge_img, coords)) {
  1043.  
  1044.         ChamferMatcher::Matching::findContourOrientations(coords, orientations);
  1045.  
  1046.         // set orientation pixel in orientation image
  1047.         for (size_t i = 0; i<coords.size();++i) {
  1048.             int x = coords[i].first;
  1049.             int y = coords[i].second;
  1050.                         //            if (orientations[i]>-CV_PI)
  1051.             //    {
  1052.             //CV_PIXEL(unsigned char, contour_img, x, y)[0] = 255;
  1053.             contour_img.at<uchar>(y,x)=255;
  1054.             //    }
  1055.             //CV_PIXEL(float, orientation_img, x, y)[0] = orientations[i];
  1056.             orientation_img.at<float>(y,x)=orientations[i];
  1057.         }
  1058.  
  1059.  
  1060.         coords.clear();
  1061.         orientations.clear();
  1062.     }
  1063.  
  1064.     //imwrite("contours.pgm", contour_img);
  1065. }
  1066.  
  1067.  
  1068. void ChamferMatcher::Matching::fillNonContourOrientations(Mat& annotated_img, Mat& orientation_img)
  1069. {
  1070.     int cols = annotated_img.cols;
  1071.     int rows = annotated_img.rows;
  1072.  
  1073.     assert(orientation_img.cols==cols && orientation_img.rows==rows);
  1074.  
  1075.     for (int y=0;y<rows;++y) {
  1076.         for (int x=0;x<cols;++x) {
  1077.             int xorig = annotated_img.at<Vec2i>(y,x)[0];
  1078.             int yorig = annotated_img.at<Vec2i>(y,x)[1];
  1079.  
  1080.             if (x!=xorig || y!=yorig) {
  1081.                 //orientation_img.at<float>(yorig,xorig)=orientation_img.at<float>(y,x);
  1082.                 orientation_img.at<float>(y,x)=orientation_img.at<float>(yorig,xorig);
  1083.             }
  1084.         }
  1085.     }
  1086. }
  1087.  
  1088.  
  1089. ChamferMatcher::Match* ChamferMatcher::Matching::localChamferDistance(Point offset, Mat& dist_img, Mat& orientation_img,
  1090.         ChamferMatcher::Template* tpl, float alpha)
  1091. {
  1092.     int x = offset.x;
  1093.     int y = offset.y;
  1094.  
  1095.     float beta = 1-alpha;
  1096.  
  1097.     std::vector<int>& addr = tpl->getTemplateAddresses(dist_img.cols);
  1098.  
  1099.     float* ptr = dist_img.ptr<float>(y)+x;
  1100.  
  1101.  
  1102.     float sum_distance = 0;
  1103.     for (size_t i=0; i<addr.size();++i) {
  1104.         if(addr[i] < (dist_img.cols*dist_img.rows) - (offset.y*dist_img.cols + offset.x)){
  1105.             sum_distance += *(ptr+addr[i]);
  1106.         }
  1107.     }
  1108.  
  1109.     float cost = (sum_distance/truncate_)/addr.size();
  1110.  
  1111.  
  1112.     if (&orientation_img!=NULL) {
  1113.         float* optr = orientation_img.ptr<float>(y)+x;
  1114.         float sum_orientation = 0;
  1115.         int cnt_orientation = 0;
  1116.  
  1117.         for (size_t i=0;i<addr.size();++i) {
  1118.  
  1119.             if(addr[i] < (orientation_img.cols*orientation_img.rows) - (offset.y*orientation_img.cols + offset.x)){
  1120.                                 if (tpl->orientations[i]>=-CV_PI && (*(optr+addr[i]))>=-CV_PI) {
  1121.                     sum_orientation += orientation_diff(tpl->orientations[i], (*(optr+addr[i])));
  1122.                     cnt_orientation++;
  1123.                 }
  1124.             }
  1125.         }
  1126.  
  1127.         if (cnt_orientation>0) {
  1128.                         cost = (float)(beta*cost+alpha*(sum_orientation/(2*CV_PI))/cnt_orientation);
  1129.         }
  1130.  
  1131.     }
  1132.  
  1133.     if(cost > 0){
  1134.         ChamferMatcher::Match* istance = new ChamferMatcher::Match();
  1135.         istance->cost = cost;
  1136.         istance->offset = offset;
  1137.         istance->tpl = tpl;
  1138.  
  1139.         return istance;
  1140.     }
  1141.  
  1142.     return NULL;
  1143. }
  1144.  
  1145.  
  1146. ChamferMatcher::Matches* ChamferMatcher::Matching::matchTemplates(Mat& dist_img, Mat& orientation_img, const ImageRange& range, float _orientation_weight)
  1147. {
  1148.  
  1149.     ChamferMatcher::Matches* pmatches(new Matches());
  1150.     // try each template
  1151.     for(size_t i = 0; i < templates.size(); i++) {
  1152.         ImageIterator* it = range.iterator();
  1153.         while (it->hasNext()) {
  1154.             location_scale_t crt = it->next();
  1155.  
  1156.             Point loc = crt.first;
  1157.             float scale = crt.second;
  1158.             Template* tpl = templates[i]->rescale(scale);
  1159.  
  1160.  
  1161.             if (loc.x-tpl->center.x<0 || loc.x+tpl->size.width/2>=dist_img.cols) continue;
  1162.             if (loc.y-tpl->center.y<0 || loc.y+tpl->size.height/2>=dist_img.rows) continue;
  1163.  
  1164.             ChamferMatcher::Match* is = localChamferDistance(loc, dist_img, orientation_img, tpl, _orientation_weight);
  1165.             if(is)
  1166.             {
  1167.                 pmatches->push_back(*is);
  1168.                 delete is;
  1169.             }
  1170.         }
  1171.  
  1172.         delete it;
  1173.     }
  1174.     return pmatches;
  1175. }
  1176.  
  1177.  
  1178.  
  1179. /**
  1180.  * Run matching using an edge image.
  1181.  * @param edge_img Edge image
  1182.  * @return a match object
  1183.  */
  1184. ChamferMatcher::Matches* ChamferMatcher::Matching::matchEdgeImage(Mat& edge_img, const ImageRange& range,
  1185.                     float _orientation_weight, int /*max_matches*/, float /*min_match_distance*/)
  1186. {
  1187.     CV_Assert(edge_img.channels()==1);
  1188.  
  1189.     Mat dist_img;
  1190.     Mat annotated_img;
  1191.     Mat orientation_img;
  1192.  
  1193.     annotated_img.create(edge_img.size(), CV_32SC2);
  1194.     dist_img.create(edge_img.size(),CV_32FC1);
  1195.     dist_img.setTo(0);
  1196.     // Computing distance transform
  1197.     computeDistanceTransform(edge_img,dist_img, annotated_img, truncate_);
  1198.  
  1199.  
  1200.     //orientation_img = NULL;
  1201.     if (use_orientation_) {
  1202.         orientation_img.create(edge_img.size(), CV_32FC1);
  1203.         orientation_img.setTo(0);
  1204.         Mat edge_clone = edge_img.clone();
  1205.         computeEdgeOrientations(edge_clone, orientation_img );
  1206.         edge_clone.release();
  1207.         fillNonContourOrientations(annotated_img, orientation_img);
  1208.     }
  1209.  
  1210.  
  1211.     // Template matching
  1212.     ChamferMatcher::Matches* pmatches = matchTemplates(    dist_img,
  1213.                                                         orientation_img,
  1214.                                                         range,
  1215.                                                         _orientation_weight);
  1216.  
  1217.  
  1218.     if (use_orientation_) {
  1219.         orientation_img.release();
  1220.     }
  1221.     dist_img.release();
  1222.     annotated_img.release();
  1223.  
  1224.     return pmatches;
  1225. }
  1226.  
  1227.  
  1228. void ChamferMatcher::addMatch(float cost, Point offset, const Template* tpl)
  1229. {
  1230.     bool new_match = true;
  1231.     for (int i=0; i<count; ++i) {
  1232.         if (std::abs(matches[i].offset.x-offset.x)+std::abs(matches[i].offset.y-offset.y)<min_match_distance_) {
  1233.             // too close, not a new match
  1234.             new_match = false;
  1235.             // if better cost, replace existing match
  1236.             if (cost<matches[i].cost) {
  1237.                 matches[i].cost = cost;
  1238.                 matches[i].offset = offset;
  1239.                 matches[i].tpl = tpl;
  1240.             }
  1241.             // re-bubble to keep ordered
  1242.             int k = i;
  1243.             while (k>0) {
  1244.                 if (matches[k-1].cost>matches[k].cost) {
  1245.                     std::swap(matches[k-1],matches[k]);
  1246.                 }
  1247.                 k--;
  1248.             }
  1249.  
  1250.             break;
  1251.         }
  1252.     }
  1253.  
  1254.     if (new_match) {
  1255.         // if we don't have enough matches yet, add it to the array
  1256.         if (count<max_matches_) {
  1257.             matches[count].cost = cost;
  1258.             matches[count].offset = offset;
  1259.             matches[count].tpl = tpl;
  1260.             count++;
  1261.         }
  1262.         // otherwise find the right position to insert it
  1263.         else {
  1264.             // if higher cost than the worst current match, just ignore it
  1265.             if (matches[count-1].cost<cost) {
  1266.                 return;
  1267.             }
  1268.  
  1269.             int j = 0;
  1270.             // skip all matches better than current one
  1271.             while (matches[j].cost<cost) j++;
  1272.  
  1273.             // shift matches one position
  1274.             int k = count-2;
  1275.             while (k>=j) {
  1276.                 matches[k+1] = matches[k];
  1277.                 k--;
  1278.             }
  1279.  
  1280.             matches[j].cost = cost;
  1281.             matches[j].offset = offset;
  1282.             matches[j].tpl = tpl;
  1283.         }
  1284.     }
  1285. }
  1286.  
  1287. void ChamferMatcher::showMatch(Mat& img, int index)
  1288. {
  1289.     if (index>=count) {
  1290.         std::cout << "Index too big.\n" << std::endl;
  1291.     }
  1292.  
  1293.     assert(img.channels()==3);
  1294.  
  1295.     Match match = matches[index];
  1296.  
  1297.     const template_coords_t& templ_coords = match.tpl->coords;
  1298.     int x, y;
  1299.     for (size_t i=0;i<templ_coords.size();++i) {
  1300.         x = match.offset.x + templ_coords[i].first;
  1301.         y = match.offset.y + templ_coords[i].second;
  1302.  
  1303.         if ( x > img.cols-1 || x < 0 || y > img.rows-1 || y < 0) continue;
  1304.         img.at<Vec3b>(y,x)[0]=0;
  1305.         img.at<Vec3b>(y,x)[2]=0;
  1306.         img.at<Vec3b>(y,x)[1]=255;
  1307.     }
  1308. }
  1309.  
  1310. void ChamferMatcher::showMatch(Mat& img, Match match)
  1311. {
  1312.     assert(img.channels()==3);
  1313.  
  1314.     const template_coords_t& templ_coords = match.tpl->coords;
  1315.     for (size_t i=0;i<templ_coords.size();++i) {
  1316.         int x = match.offset.x + templ_coords[i].first;
  1317.         int y = match.offset.y + templ_coords[i].second;
  1318.         if ( x > img.cols-1 || x < 0 || y > img.rows-1 || y < 0) continue;
  1319.         img.at<Vec3b>(y,x)[0]=0;
  1320.         img.at<Vec3b>(y,x)[2]=0;
  1321.         img.at<Vec3b>(y,x)[1]=255;
  1322.     }
  1323.     match.tpl->show();
  1324. }
  1325.  
  1326. const ChamferMatcher::Matches& ChamferMatcher::matching(Template& tpl, Mat& image_){
  1327.     chamfer_->addTemplate(tpl);
  1328.  
  1329.     matches.clear();
  1330.     matches.resize(max_matches_);
  1331.     count = 0;
  1332.  
  1333.  
  1334.     Matches* matches_ = chamfer_->matchEdgeImage(    image_,
  1335.                                                     ChamferMatcher::
  1336.                                                         SlidingWindowImageRange(image_.cols,
  1337.                                                                                 image_.rows,
  1338.                                                                                 pad_x,
  1339.                                                                                 pad_y,
  1340.                                                                                 scales,
  1341.                                                                                 minScale,
  1342.                                                                                 maxScale),
  1343.                                                     orientation_weight,
  1344.                                                     max_matches_,
  1345.                                                     min_match_distance_);
  1346.  
  1347.  
  1348.  
  1349.     for(int i = 0; i < (int)matches_->size(); i++){
  1350.         addMatch(matches_->at(i).cost, matches_->at(i).offset, matches_->at(i).tpl);
  1351.     }
  1352.  
  1353.     matches_->clear();
  1354.     delete matches_;
  1355.     matches_ = NULL;
  1356.  
  1357.     matches.resize(count);
  1358.  
  1359.  
  1360.     return matches;
  1361.  
  1362. }
  1363.  
  1364.  
  1365. int chamferMatching2( Mat& img, Mat& templ,
  1366.                     std::vector<std::vector<Point> >& results, std::vector<float>& costs,
  1367.                     double templScale, int maxMatches, double minMatchDistance, int padX,
  1368.                     int padY, int scales, double minScale, double maxScale,
  1369.                     double orientationWeight, double truncate )
  1370. {
  1371.     CV_Assert(img.type() == CV_8UC1 && templ.type() == CV_8UC1);
  1372.  
  1373.     ChamferMatcher matcher_(maxMatches, (float)minMatchDistance, padX, padY, scales,
  1374.                             (float)minScale, (float)maxScale,
  1375.                             (float)orientationWeight, (float)truncate);
  1376.  
  1377.     ChamferMatcher::Template template_(templ, (float)templScale);
  1378.     ChamferMatcher::Matches match_instances = matcher_.matching(template_, img);
  1379.  
  1380.     size_t i, nmatches = match_instances.size();
  1381.  
  1382.     results.resize(nmatches);
  1383.     costs.resize(nmatches);
  1384.  
  1385.     int bestIdx = -1;
  1386.     double minCost = DBL_MAX;
  1387.  
  1388.     for( i = 0; i < nmatches; i++ )
  1389.     {
  1390.         const ChamferMatcher::Match& match = match_instances[i];
  1391.         double cval = match.cost;
  1392.         if( cval < minCost)
  1393.         {
  1394.             minCost = cval;
  1395.             bestIdx = (int)i;
  1396.         }
  1397.         costs[i] = (float)cval;
  1398.        
  1399.         const template_coords_t& templ_coords = match.tpl->coords;
  1400.         std::vector<Point>& templPoints = results[i];
  1401.         size_t j, npoints = templ_coords.size();
  1402.         templPoints.resize(npoints);
  1403.  
  1404.         for (j = 0; j < npoints; j++ )
  1405.         {
  1406.             int x = match.offset.x + templ_coords[j].first;
  1407.             int y = match.offset.y + templ_coords[j].second;
  1408.             templPoints[j] = Point(x,y);
  1409.         }
  1410.     }
  1411.     std::cout << minCost;
  1412.     return bestIdx;
  1413. }
  1414.  
  1415. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement