Centrist.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /**
  2. * @file Centrist.cpp
  3. * @brief Implementation of the Centrist feature published in "CENTRIST: A Visual Descriptor for Scene Categorization" (PAMI 2011)
  4. * @author Alexander Lütz
  5. * @date 12/06/2011
  6. */
  7. #include <iostream>
  8. #include "vislearning/features/localfeatures/Centrist.h"
  9. #include "core/vector/VVector.h"
  10. using namespace OBJREC;
  11. using namespace std;
  12. using namespace NICE;
  13. /* protected methods*/
  14. /**
  15. * @brief: perform centrist transformation for a single pixel
  16. * @author Alexander Lütz
  17. * @date 12/06/2011
  18. */
  19. //TODO maybe inline?
  20. int CensusTransform(const NICE::Image & img, const int & x, const int & y)
  21. {
  22. int index(0);
  23. if (! img.isWithinImage(x,y)) return index;
  24. if( (img.isWithinImage(x-1,y-1)) && (img.getPixelInt(x,y)<=img.getPixelInt(x-1,y-1)) ) index |= 0x80;
  25. if( (img.isWithinImage(x-1,y)) && (img.getPixelInt(x,y)<=img.getPixelInt(x-1,y)) ) index |= 0x40;
  26. if( (img.isWithinImage(x-1,y+1)) && (img.getPixelInt(x,y)<=img.getPixelInt(x-1,y+1)) ) index |= 0x20;
  27. if( (img.isWithinImage(x,y-1)) && (img.getPixelInt(x,y)<=img.getPixelInt(x,y-1)) ) index |= 0x10;
  28. if( (img.isWithinImage(x,y+1)) && (img.getPixelInt(x,y)<=img.getPixelInt(x,y+1)) ) index |= 0x08;
  29. if( (img.isWithinImage(x+1,y-1)) && (img.getPixelInt(x,y)<=img.getPixelInt(x+1,y-1)) ) index |= 0x04;
  30. if( (img.isWithinImage(x+1,y)) && (img.getPixelInt(x,y)<=img.getPixelInt(x+1,y)) ) index |= 0x02;
  31. if( (img.isWithinImage(x+1,y+1)) && (img.getPixelInt(x,y)<=img.getPixelInt(x+1,y+1)) ) index |= 0x01;
  32. return index;
  33. }
  34. /**
  35. * @brief: perform centrist transformation for a single pixel
  36. * @author Alexander Lütz
  37. * @date 12/06/2011
  38. */
  39. //TODO maybe inline?
  40. int CensusTransform(const NICE::ColorImage & img, const int & x, const int & y, const int & channel)
  41. {
  42. int index(0);
  43. if (! img.isWithinImage(x,y)) return index;
  44. if( (img.isWithinImage(x-1,y-1)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x-1,y-1, channel)) ) index |= 0x80;
  45. if( (img.isWithinImage(x-1,y)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x-1,y, channel)) ) index |= 0x40;
  46. if( (img.isWithinImage(x-1,y+1)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x-1,y+1, channel)) ) index |= 0x20;
  47. if( (img.isWithinImage(x,y-1)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x,y-1, channel)) ) index |= 0x10;
  48. if( (img.isWithinImage(x,y+1)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x,y+1, channel)) ) index |= 0x08;
  49. if( (img.isWithinImage(x+1,y-1)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x+1,y-1, channel)) ) index |= 0x04;
  50. if( (img.isWithinImage(x+1,y)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x+1,y, channel)) ) index |= 0x02;
  51. if( (img.isWithinImage(x+1,y+1)) && (img.getPixelInt(x,y, channel)<=img.getPixelInt(x+1,y+1, channel)) ) index |= 0x01;
  52. return index;
  53. }
  54. /**
  55. * @brief: generate CT histogram for a given rectangle: pixels in [xi yi]-(xa,ya) -- including (xi,yi) but excluding (xa,ya)
  56. * @author Alexander Lütz
  57. * @date 12/06/2011
  58. */
  59. void Centrist::GenerateHistForOneRect(const NICE::Image & img, const int & xi, const int & xa, const int & yi, const int & ya, NICE::Vector & feature)
  60. {
  61. // double pixelSum(0.0);
  62. // double pixelSquare(0.0);
  63. feature.resize(256);
  64. feature.set(0.0);
  65. for (int j = yi; j < ya; j++)
  66. {
  67. for (int i = xi; i < xa; i++)
  68. {
  69. // pixelSum += img.getPixelInt(i,j);
  70. // pixelSquare += img.getPixelInt(i,j)*img.getPixelInt(i,j);
  71. feature[CensusTransform(img,i,j)]++;
  72. }
  73. }
  74. // const double size ( (xa-xi)*(ya-yi));
  75. // normalize histogram to have 0 mean, remove the first and last entry, and normalize to have unit norm
  76. double sum(feature.Sum()/256.0);//shift more efficient?
  77. // normalize histogram to have 0 mean
  78. //but why?
  79. feature -= sum;
  80. //remove the first and last entry
  81. feature[0] = 0.0;
  82. feature[255] = 0.0;
  83. //normalization - here done using unit L2-norm
  84. feature.normalizeL2();
  85. }
  86. /**
  87. * @brief: generate CT histogram for a given rectangle: pixels in [xi yi]-(xa,ya) -- including (xi,yi) but excluding (xa,ya)
  88. * @author Alexander Lütz
  89. * @date 12/06/2011
  90. */
  91. void Centrist::GenerateHistForOneRect(const NICE::ColorImage & img, const int & xi, const int & xa, const int & yi, const int & ya, NICE::Vector & feature)
  92. {
  93. // double pixelSum(0.0);
  94. // double pixelSquare(0.0);
  95. int nrChannel (img.channels());
  96. feature.resize(256*nrChannel);
  97. feature.set(0.0);
  98. for (int channel = 0; channel < nrChannel; channel++)
  99. {
  100. for (int j = yi; j < ya; j++)
  101. {
  102. for (int i = xi; i < xa; i++)
  103. {
  104. // pixelSum += img.getPixelInt(i,j, channel);
  105. // pixelSquare += img.getPixelInt(i,j, channel)*img.getPixelInt(i,j, channel);
  106. feature[256*channel+CensusTransform(img,i,j,channel)]++;
  107. }
  108. }
  109. }
  110. // const double size ( (xa-xi)*(ya-yi))
  111. // normalize histogram to have 0 mean, remove the first and last entry, and normalize to have unit norm
  112. double sum(feature.Sum()/256.0);//shift more efficient?
  113. // normalize histogram to have 0 mean
  114. //but why?
  115. feature -= sum;
  116. //remove the first and last entry
  117. feature[0] = 0.0;
  118. feature[255] = 0.0;
  119. //normalization - here done using unit L2-norm
  120. feature.normalizeL2();
  121. }
  122. /**
  123. * @brief Computes several CENTRIST descriptors for each of the given positions om a local neighborhood
  124. * @author Alexander Lütz
  125. * @date 12/06/2011
  126. */
  127. void Centrist::computeDesc( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors )
  128. {
  129. descriptors.clear();
  130. for (NICE::VVector::const_iterator it = positions.begin(); it != positions.end(); it++)
  131. {
  132. NICE::Vector descriptor;
  133. GenerateHistForOneRect(img, (*it)[0]-sizeNeighborhood/2, (*it)[0]+sizeNeighborhood/2, (*it)[1]-sizeNeighborhood/2, (*it)[1]+sizeNeighborhood/2, descriptor);
  134. descriptors.push_back(descriptor);
  135. }
  136. }
  137. /**
  138. * @brief Computes several CENTRIST descriptors for each of the given positions om a local neighborhood
  139. * @author Alexander Lütz
  140. * @date 12/06/2011
  141. */
  142. void Centrist::computeDesc( const NICE::ColorImage & img, NICE::VVector & positions, NICE::VVector & descriptors )
  143. {
  144. descriptors.clear();
  145. for (NICE::VVector::const_iterator it = positions.begin(); it != positions.end(); it++)
  146. {
  147. NICE::Vector descriptor;
  148. GenerateHistForOneRect(img, (*it)[0]-sizeNeighborhood/2, (*it)[0]+sizeNeighborhood/2, (*it)[1]-sizeNeighborhood/2, (*it)[1]+sizeNeighborhood/2, descriptor);
  149. descriptors.push_back(descriptor);
  150. }
  151. }
  152. /* public methods*/
  153. /**
  154. * @brief Default constructor
  155. * @author Alexander Lütz
  156. * @date 12/06/2011
  157. */
  158. Centrist::Centrist()
  159. {
  160. sizeNeighborhood = 16;
  161. }
  162. /**
  163. * @brief Recommended constructor
  164. * @author Alexander Lütz
  165. * @date 12/06/2011
  166. */
  167. Centrist::Centrist( const Config *conf, const std::string & section )
  168. {
  169. sizeNeighborhood = conf->gI(section, "sizeNeighborhood", 16);
  170. }
  171. /**
  172. * @brief Default destructor
  173. * @author Alexander Lütz
  174. * @date 12/06/2011
  175. */
  176. Centrist::~Centrist()
  177. {
  178. }
  179. /**
  180. * @brief Computes several CENTRIST descriptors for each of the given positions on a local neighborhood
  181. * @author Alexander Lütz
  182. * @date 12/06/2011
  183. */
  184. int Centrist::getDescriptors ( const NICE::Image & img, VVector & positions, VVector & descriptors )
  185. {
  186. computeDesc(img, positions, descriptors);
  187. return 0;
  188. }
  189. /**
  190. * @brief Computes several CENTRIST descriptors for each of the given positions on a local neighborhood
  191. * @author Alexander Lütz
  192. * @date 12/06/2011
  193. */
  194. int Centrist::getDescriptors ( const NICE::ColorImage & img, NICE::VVector & positions, NICE::VVector & descriptors)
  195. {
  196. computeDesc(img, positions, descriptors);
  197. return 0;
  198. }
  199. /**
  200. * @brief Visualizes CENTRIST descriptors, not implemented yet!
  201. * @author Alexander Lütz
  202. * @date 12/06/2011
  203. */
  204. void Centrist::visualizeFeatures ( NICE::Image & mark,
  205. const VVector & positions,
  206. size_t color ) const
  207. {
  208. // ice::Image mark_ice = ice::NewImg ( mark.width(),
  209. // mark.height(), 255 );
  210. // for ( size_t k = 0 ; k < positions.size() ; k++ )
  211. // {
  212. // const NICE::Vector & pos = positions[k];
  213. // ice::Matrix points ( 0, 2 );
  214. // const int size = 6;
  215. // points.Append ( ice::Vector(-size, -size) );
  216. // points.Append ( ice::Vector(-size, size) );
  217. // points.Append ( ice::Vector(size, size) );
  218. // points.Append ( ice::Vector(size, -size) );
  219. //
  220. // ice::Trafo tr;
  221. //
  222. // tr.Scale ( 0, 0, pos[2] );
  223. // tr.Rotate ( 0, 0, pos[3] );
  224. // tr.Shift ( pos[0], pos[1] );
  225. //
  226. // ice::TransformList(tr, points);
  227. //
  228. // for ( int j = 0 ; j < points.rows(); j++ )
  229. // {
  230. // if (points[j][0] < 0 )
  231. // points[j][0] = 0;
  232. // if (points[j][0] >= mark_ice->xsize)
  233. // points[j][0] = mark_ice->xsize - 1;
  234. // if (points[j][1] < 0 )
  235. // points[j][1] = 0;
  236. // if (points[j][1] >= mark_ice->ysize)
  237. // points[j][1] = mark_ice->ysize - 1;
  238. // }
  239. // ice::DrawPolygon ( points, color, mark_ice );
  240. // }
  241. //
  242. // for ( unsigned int y = 0 ; y < mark.height(); y++ )
  243. // for ( unsigned int x = 0 ; x < mark.width(); x++ )
  244. // mark.setPixel(x,y, GetVal(mark_ice,x,y));
  245. }