harrislike.cc

00001 /*
00002 
00003     This file is part of the FAST-ER machine learning system.
00004     Copyright (C) 2008  Edward Rosten and Los Alamos National Laboratory
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License along
00017     with this program; if not, write to the Free Software Foundation, Inc.,
00018     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00019 */
00020 #include <cvd/image.h>
00021 #include <cvd/convolution.h>
00022 #include <gvars3/instances.h>
00023 #include <vector>
00024 
00025 #include "harrislike.h"
00026 
00027 using namespace std;
00028 using namespace CVD;
00029 using namespace GVars3;
00030 
00031 
00032 
00033 ////////////////////////////////////////////////////////////////////////////////
00034 //
00035 // Harris-like corners.
00036 // 
00037 
00038 ///\cond never
00039 template<class C> inline C sq(const C& c)
00040 {
00041     return c*c;
00042 }
00043 
00044 
00045 struct HarrisScore
00046 {
00047     static float Compute(float xx, float xy, float yy)
00048     {
00049         return (xx * yy - xy * xy) - 0.04 * sq(xx + yy);
00050     }
00051 };
00052 
00053 struct ShiTomasiScore
00054 {
00055     static float Compute(float xx, float xy, float yy)
00056     {
00057         float l1 = xx + yy + sqrt(sq(xx - yy)+4.0*xy*xy);   
00058         float l2 = xx + yy - sqrt(sq(xx - yy)+4.0*xy*xy);
00059         return min(abs(l1), abs(l2));
00060     }
00061 };
00062 
00063 struct PosInserter
00064 {
00065     static void insert(vector<ImageRef>& i, const pair<float, ImageRef>& p)
00066     {
00067         i.push_back(p.second);
00068     }
00069 };
00070 
00071 struct PairInserter
00072 {
00073     static void insert(vector<pair<float, ImageRef> >& i, const pair<float, ImageRef>& p)
00074     {
00075         i.push_back(p);
00076     }
00077 };
00078 ///\endcond
00079 
00080 template<class Score, class Inserter, class C, class B> void harris_like(const Image<B>& i, C& c, unsigned int N, float blur, float sigmas)
00081 {
00082 
00083     Image<float> xx(i.size()), xy(i.size()), yy(i.size());
00084 
00085     zeroBorders(xx);
00086     zeroBorders(xy);
00087     zeroBorders(yy);
00088 
00089     typedef typename Pixel::traits<B>::wider_type gType;
00090     
00091     //Compute gradients
00092     for(int y=1; y < i.size().y - 1; y++)
00093         for(int x=1; x < i.size().x - 1; x++)
00094         {
00095             gType gx = (gType)i[y][x-1] - i[y][x+1];
00096             gType gy = (gType)i[y-1][x] - i[y+1][x];
00097             
00098             //Compute the gradient moments
00099             xx[y][x] = gx * gx;
00100             xy[y][x] = gx * gy;
00101             yy[y][x] = gy * gy;
00102         }
00103 
00104     convolveGaussian_fir(xx, xx, blur, sigmas);
00105     convolveGaussian_fir(xy, xy, blur, sigmas);
00106     convolveGaussian_fir(yy, yy, blur, sigmas);
00107     
00108     //Avoid computing the score along the image borders where the
00109     //result of the convolution is not valid.
00110     int kspread = (int)ceil(sigmas * blur);
00111 
00112     //Compute harris score
00113     for(int y=kspread; y < i.size().y-kspread; y++)
00114         for(int x=kspread; x <i.size().x-kspread; x++)
00115             xx[y][x] = Score::Compute(xx[y][x], xy[y][x], yy[y][x]);
00116 
00117     vector<pair<float, ImageRef> > corners;
00118     corners.reserve(10000);
00119 
00120     //Find local maxima
00121     for(int y=kspread; y < i.size().y-kspread; y++)
00122         for(int x=kspread; x <i.size().x-kspread; x++)
00123         {
00124             float c = xx[y][x];
00125 
00126             if( c > xx[y-1][x-1]  &&
00127                 c > xx[y-1][x+0]  &&
00128                 c > xx[y-1][x+1]  &&
00129                 c > xx[y-0][x-1]  &&
00130                 c > xx[y-0][x+1]  &&
00131                 c > xx[y+1][x-1]  &&
00132                 c > xx[y+1][x+0]  &&
00133                 c > xx[y+1][x+1])
00134             {
00135                 corners.push_back(make_pair(-c, ImageRef(x, y)));
00136             }
00137         }
00138 
00139     if(corners.size() > N)
00140     {
00141         nth_element(corners.begin(), corners.begin() + N, corners.end());
00142         corners.resize(N);
00143     }
00144 
00145 
00146     for(unsigned int i=0; i < corners.size(); i++)
00147         Inserter::insert(c, corners[i]);
00148 }
00149 
00150 
00151 void HarrisDetector(const Image<float>& i, vector<pair<float, ImageRef> >& c, unsigned int N, float blur, float sigmas)
00152 {
00153     harris_like<HarrisScore, PairInserter>(i, c, N, blur, sigmas);
00154 }
00155 
00156 
00157 void HarrisDetect::operator()(const CVD::Image<CVD::byte>& i, std::vector<CVD::ImageRef>& c, unsigned int N) const 
00158 {
00159     float blur = GV3::get<float>("harris.blur", 2.5, 1);
00160     float sigmas = GV3::get<float>("harris.sigmas", 2.0, 1);
00161     harris_like<HarrisScore,PosInserter>(i, c, N, blur, sigmas);
00162 }
00163 
00164 void ShiTomasiDetect::operator()(const CVD::Image<CVD::byte>& i, std::vector<CVD::ImageRef>& c, unsigned int N) const
00165 {
00166     float blur = GV3::get<float>("shitomasi.blur", 2.5, 1);
00167     float sigmas = GV3::get<float>("shitomasi.sigmas", 2.0, 1);
00168     harris_like<ShiTomasiScore, PosInserter>(i, c, N, blur, sigmas);
00169 }

Generated on Mon Mar 2 12:47:12 2009 for FAST-ER by  doxygen 1.5.3