TuttleOFX
1
|
00001 #ifndef _TERRY_FILTER_LOCALMAXIMA_HPP_ 00002 #define _TERRY_FILTER_LOCALMAXIMA_HPP_ 00003 00004 #include <terry/channel.hpp> 00005 #include <terry/math/Rect.hpp> 00006 #include <terry/algorithm/transform_pixels.hpp> 00007 #include <terry/numeric/operations.hpp> 00008 #include <terry/numeric/init.hpp> 00009 #include <terry/numeric/assign_minmax.hpp> 00010 00011 #include <boost/assert.hpp> 00012 00013 00014 namespace terry { 00015 namespace filter { 00016 00017 00018 /** 00019 * Computation of gradient norm local maxima in regard of gradient direction 00020 * 00021 * there are 4 cases: 00022 * 00023 * The X marks the pixel in question, and each 00024 * C B of the quadrants for the gradient vector 00025 * O----0----0 fall into two cases, divided by the 45 00026 * D | | A degree line. In one case the gradient 00027 * | | vector is more horizontal, and in the other 00028 * O X O it is more vertical. There are eight 00029 * | | divisions, but for the non-maximum suppression 00030 * (A)| |(D) we are only worried about 4 of them since we 00031 * O----O----O use symmetric points about the center pixel. 00032 * (B) (C) 00033 */ 00034 template<class SView, class DView=SView> 00035 struct pixel_locator_gradientLocalMaxima_t 00036 { 00037 typedef typename SView::locator SLocator; 00038 typedef typename SView::value_type SPixel; 00039 typedef typename boost::gil::channel_type<SPixel>::type SChannel; 00040 typedef typename terry::channel_base_type<SChannel>::type SType; 00041 typedef typename SLocator::cached_location_t SCachedLocation; 00042 00043 typedef typename DView::locator DLocator; 00044 typedef typename DView::value_type DPixel; 00045 00046 DPixel _black; 00047 const SLocator _loc_ref; 00048 // LT CT RT 00049 // LC RC 00050 // LB CB RB 00051 const SCachedLocation LT; 00052 const SCachedLocation CT; 00053 const SCachedLocation RT; 00054 const SCachedLocation LC; 00055 const SCachedLocation RC; 00056 const SCachedLocation LB; 00057 const SCachedLocation CB; 00058 const SCachedLocation RB; 00059 00060 static const unsigned int vecX = 0; 00061 static const unsigned int vecY = 1; 00062 static const unsigned int norm = 2; 00063 00064 pixel_locator_gradientLocalMaxima_t( const SView& src ) 00065 : _loc_ref(src.xy_at(0,0)) 00066 , LT(_loc_ref.cache_location(-1,-1)) 00067 , CT(_loc_ref.cache_location( 0,-1)) 00068 , RT(_loc_ref.cache_location( 1,-1)) 00069 00070 , LC(_loc_ref.cache_location(-1, 0)) 00071 , RC(_loc_ref.cache_location( 1, 0)) 00072 00073 , LB(_loc_ref.cache_location(-1, 1)) 00074 , CB(_loc_ref.cache_location( 0, 1)) 00075 , RB(_loc_ref.cache_location( 1, 1)) 00076 { 00077 using namespace terry::numeric; 00078 pixel_assigns_min( _black ); 00079 } 00080 00081 DPixel operator()( const SLocator& src ) const 00082 { 00083 using namespace terry; 00084 00085 SType g1; 00086 SType g2; 00087 00088 if( (*src)[vecX] == 0 && (*src)[vecY] == 0 ) 00089 { 00090 return _black; 00091 } 00092 // A 00093 if( ((*src)[vecY] <= 0 && (*src)[vecX] > -(*src)[vecY]) || 00094 ((*src)[vecY] >= 0 && (*src)[vecX] < -(*src)[vecY]) ) 00095 { 00096 SType d = 0.0; 00097 if( (*src)[vecX] ) 00098 { 00099 d = std::abs( (*src)[vecY] / (*src)[vecX] ); 00100 } 00101 SType invd = 1.0 - d; 00102 // __________ 00103 // |__|__|RT| 00104 // |LC|__|RC| 00105 // |LB|__|__| 00106 g1 = src[RC][norm] * invd + src[RT][norm] * d; 00107 g2 = src[LC][norm] * invd + src[LB][norm] * d; 00108 } 00109 // B 00110 else if ( ((*src)[vecX] > 0 && -(*src)[vecY] >= (*src)[vecX]) || 00111 ((*src)[vecX] < 0 && -(*src)[vecY] <= (*src)[vecX]) ) 00112 { 00113 SType d = 0.0; 00114 if( (*src)[vecY] ) 00115 { 00116 d = std::abs( (*src)[vecX] / (*src)[vecY] ); 00117 } 00118 SType invd = 1.0 - d; 00119 // __________ 00120 // |__|CT|RT| 00121 // |__|__|__| 00122 // |LB|CB|__| 00123 g1 = src[CT][norm] * invd + src[RT][norm] * d; 00124 g2 = src[CB][norm] * invd + src[LB][norm] * d; 00125 } 00126 // C 00127 else if( ((*src)[vecX] <= 0 && (*src)[vecX] > (*src)[vecY]) || 00128 ((*src)[vecX] >= 0 && (*src)[vecX] < (*src)[vecY]) ) 00129 { 00130 SType d = 0.0; 00131 if( (*src)[vecY] ) 00132 { 00133 d = std::abs( (*src)[vecX] / (*src)[vecY] ); 00134 } 00135 SType invd = 1.0 - d; 00136 // __________ 00137 // |LT|CT|__| 00138 // |__|__|__| 00139 // |__|CB|RB| 00140 g1 = src[CT][norm] * invd + src[LT][norm] * d; 00141 g2 = src[CB][norm] * invd + src[RB][norm] * d; 00142 } 00143 // D 00144 // else if( ((*src)[vecY] < 0 && (*src)[vecX] <= (*src)[vecY]) || 00145 // ((*src)[vecY] > 0 && (*src)[vecX] >= (*src)[vecY]) ) 00146 else 00147 { 00148 BOOST_ASSERT( 00149 ( (*src)[vecY] < 0 && (*src)[vecX] <= (*src)[vecY] ) || 00150 ( (*src)[vecY] > 0 && (*src)[vecX] >= (*src)[vecY] ) ); 00151 SType d = 0.0; 00152 if( (*src)[vecX] ) 00153 { 00154 d = std::abs( (*src)[vecY] / (*src)[vecX] ); 00155 } 00156 SType invd = 1.0 - d; 00157 // __________ 00158 // |LT|__|__| 00159 // |LC|__|RC| 00160 // |__|__|RB| 00161 g1 = src[LC][norm] * invd + src[LT][norm] * d; 00162 g2 = src[RC][norm] * invd + src[RB][norm] * d; 00163 } 00164 00165 if( (*src)[norm] >= g1 && (*src)[norm] >= g2 ) 00166 { 00167 // wins ! 00168 DPixel dst; 00169 static_fill( dst, (*src)[norm] ); 00170 return dst; 00171 } 00172 return _black; 00173 } 00174 }; 00175 00176 00177 template<class SView, class DView> 00178 void applyLocalMaxima( const SView& srcView, DView& dstView ) 00179 { 00180 using namespace terry::numeric; 00181 00182 typedef typename DView::value_type DPixel; 00183 DPixel pixelZero; pixel_zeros_t<DPixel>()( pixelZero ); 00184 00185 // todo: only fill borders !! 00186 fill_pixels( dstView, pixelZero ); 00187 00188 terry::algorithm::transform_pixels_locator( 00189 srcView, getBounds<std::ptrdiff_t>(srcView), 00190 dstView, getBounds<std::ptrdiff_t>(dstView), 00191 getBounds<std::ptrdiff_t>(dstView), 00192 terry::filter::pixel_locator_gradientLocalMaxima_t<SView,DView>(srcView) 00193 ); 00194 } 00195 00196 00197 00198 00199 } 00200 } 00201 00202 #endif