Morph.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. #include "core/image/Morph.h"
  2. #include "core/image/ImageTools.h"
  3. #include <math.h>
  4. #include <limits>
  5. #include <iostream>
  6. using namespace std;
  7. namespace NICE {
  8. // little helper function
  9. static inline size_t getHistRank(const Histogram& hist, const size_t& rank)
  10. {
  11. uint sum = 0;
  12. for(Histogram::const_iterator i=hist.begin(); i!=hist.end(); ++i) {
  13. sum += *i;
  14. if(sum<rank) continue;
  15. return(i-hist.begin());
  16. }
  17. return hist.size();
  18. }
  19. static inline Ipp32s erodeNext(const Image& src, Histogram& hist, const int& size,
  20. int& hist_val, int& hist_min, const int& x, const int& y)
  21. {
  22. int i;
  23. i=-size;
  24. do {
  25. hist_val = src.getPixelQuick(x+1,y+i);
  26. ++hist[hist_val];
  27. hist_min = (hist_val<hist_min)?hist_val:hist_min;
  28. ++i;
  29. } while(i<=size);
  30. i=-size;
  31. do {
  32. hist_val = src.getPixelQuick(x-2,y+i);
  33. --hist[hist_val];
  34. if( (hist_val-hist_min)==0 )
  35. if(hist[hist_val]==0)
  36. while(hist[hist_min]==0)
  37. ++hist_min;
  38. ++i;
  39. } while(i<=size);
  40. return hist_min;
  41. }
  42. static inline Ipp32s dilateNext(const Image& src, Histogram& hist, const int& isize,
  43. int& hist_val, int& hist_max, int x, int y)
  44. {
  45. int i;
  46. i=-isize;
  47. do {
  48. hist_val = src.getPixelQuick(x+isize,y+i);
  49. ++hist[hist_val];
  50. hist_max = (hist_val>hist_max)?hist_val:hist_max;
  51. ++i;
  52. } while(i<=isize);
  53. i=-isize;
  54. do {
  55. hist_val = src.getPixelQuick(x-isize-1,y+i);
  56. --hist[hist_val];
  57. if((hist_val-hist_max)==0)
  58. if(hist[hist_max]==0)
  59. while(hist[hist_max]==0)
  60. --hist_max;
  61. ++i;
  62. } while(i<=isize);
  63. return hist_max;
  64. }
  65. static inline Ipp32s medianNext(const Ipp8u& hist_val, Histogram& hist, int& hist_temp,
  66. int& hist_med, uint& hist_lower, uint& hist_upper, bool add=true)
  67. {
  68. if(add) {
  69. ++hist[hist_val];
  70. if(hist_med<0) {
  71. hist_lower = hist_upper = 0;
  72. hist_med = hist_val;
  73. }
  74. else if(hist_val < hist_med)
  75. ++hist_lower;
  76. else if(hist_val > hist_med)
  77. ++hist_upper;
  78. }
  79. else {
  80. --hist[hist_val];
  81. if(hist_val < hist_med)
  82. --hist_lower;
  83. else if(hist_val > hist_med)
  84. --hist_upper;
  85. }
  86. if(hist_lower>hist[hist_med]+hist_upper) {
  87. hist_temp = hist_med-1;
  88. while(hist[hist_temp]==0)
  89. --hist_temp;
  90. hist_lower -= hist[hist_temp];
  91. hist_upper += hist[hist_med];
  92. hist_med = hist_temp;
  93. }
  94. else if(hist_upper>=hist[hist_med]+hist_lower) {
  95. hist_temp = hist_med+1;
  96. while(hist[hist_temp]==0)
  97. ++hist_temp;
  98. hist_upper -= hist[hist_temp];
  99. hist_lower += hist[hist_med];
  100. hist_med = hist_temp;
  101. }
  102. return hist_med;
  103. }
  104. // // // // // Ranking Operations
  105. Image* rank(const Image& src, const uint& size, const uint& rank, Image* dst)
  106. {
  107. if( rank>((2*size+1)*(2*size+1)) || rank<1 )
  108. fthrow(ImageException,"Rank smaller 1 or bigger than (2*size+1)x(2*size+1) not allowed.");
  109. Image* result = createResultBuffer(src, dst);
  110. copyBorder ( src, size, size, dst );
  111. int isize = size;
  112. uint msize = 2*isize+1;
  113. const Image *imgSub = NULL;
  114. Histogram hist;
  115. int xstart = size+1;
  116. int xend = src.width()-isize;
  117. int ystart = size;
  118. int yend = src.height()-isize;
  119. Image::Pixel *p;
  120. for(int y=ystart; y<yend; ++y) {
  121. delete imgSub;
  122. imgSub = src.createSubImage(Rect(0,y-isize,msize,msize));
  123. hist = Histogram(*imgSub,0,256);
  124. p = result->getPixelPointerXY(isize,y);
  125. *p++ = getHistRank(hist, rank);
  126. for(int x=xstart; x<xend; ++x,++p) {
  127. for(int i=-isize; i<=+isize; ++i) {
  128. hist[src.getPixelQuick(x-isize-1,y+i)] -= 1;
  129. hist[src.getPixelQuick(x+isize ,y+i)] += 1;
  130. }
  131. *p = getHistRank(hist, rank);
  132. }
  133. }
  134. // clean up
  135. delete imgSub;
  136. return result;
  137. };
  138. Image* erode(const Image& src, Image* dst, const size_t& size)
  139. {
  140. Image* result = createResultBuffer(src, dst);
  141. copyBorder ( src, size, size, dst );
  142. #ifdef NICE_USELIB_IPP
  143. IppStatus ret;
  144. IppiPoint anchor = {(int)size, (int)size};
  145. IppiSize ROIsize = {(int)(src.width()-2*size), (int)(src.height()-2*size)};
  146. // 3x3
  147. if(size==1) {
  148. ret = ippiErode3x3_8u_C1R(src.getPixelPointerXY(1,1),
  149. src.getStepsize(),
  150. result->getPixelPointerXY(1,1),
  151. result->getStepsize(), ROIsize);
  152. }
  153. else
  154. {
  155. IppiSize maskSize = {(int)(2*size+1), (int)(2*size+1)};
  156. Ipp8u *pMask = new Ipp8u[(2*size+1)*(2*size+1)];
  157. ippiSet_8u_C1R(1,pMask,2*size+1,maskSize);
  158. ret = ippiErode_8u_C1R(src.getPixelPointerXY(anchor.x, anchor.y),
  159. src.getStepsize(),
  160. result->getPixelPointerXY(anchor.x, anchor.y),
  161. result->getStepsize(),
  162. ROIsize, pMask, maskSize, anchor);
  163. }
  164. if(ret!=ippStsNoErr)
  165. fthrow(ImageException, ippGetStatusString(ret));
  166. #else // NICE_USELIB_IPP
  167. int isize = size;
  168. int xstart = size+1;
  169. int xend = src.width()-isize;
  170. Histogram hist(256);
  171. int hist_min, hist_val;
  172. const Image::Pixel* pSrc;
  173. Image::Pixel* pDst;
  174. for(int y=size; y<src.height()-isize; ++y) {
  175. hist = 0;
  176. hist_min = std::numeric_limits<int>::max();
  177. for(int sy=-isize; sy<=isize; ++sy) {
  178. for(int sx=-isize; sx<=+isize; ++sx,++pSrc) {
  179. hist_val = src.getPixelQuick(size+sx,y+sy);
  180. ++hist[hist_val];
  181. if(hist_val<hist_min)
  182. hist_min = hist_val;
  183. }
  184. }
  185. pDst = result->getPixelPointerXY(isize,y);
  186. *pDst = hist_min;
  187. ++pDst;
  188. pSrc = src.getPixelPointerXY(xstart,y);
  189. for(int x=xstart; x<xend; ++x,++pSrc,++pDst)
  190. *pDst = erodeNext(src,hist,isize,hist_val,hist_min,x,y);
  191. }
  192. #endif // NICE_USELIB_IPP
  193. return result;
  194. }
  195. Image* median(const Image& src, Image* dst, const size_t& size)
  196. {
  197. Image* result = createResultBuffer(src, dst);
  198. copyBorder ( src, size, size, dst );
  199. #ifdef NICE_USELIB_IPP
  200. IppiSize maskSize = {(int)(2*size+1), (int)(2*size+1)};
  201. IppiPoint anchor = {(int)size, (int)size};
  202. IppiSize ROIsize = {(int)(src.width()-2*size), (int)(src.height()-2*size)};
  203. IppStatus ret = ippiFilterMedian_8u_C1R(src.getPixelPointerXY(anchor.x, anchor.y),
  204. src.getStepsize(),
  205. result->getPixelPointerXY(anchor.x, anchor.y),
  206. result->getStepsize(),
  207. ROIsize, maskSize, anchor);
  208. if(ret!=ippStsNoErr)
  209. fthrow(ImageException, ippGetStatusString(ret));
  210. #else // NICE_USELIB_IPP
  211. int isize = size;
  212. int xstart = size+1;
  213. int xend = src.width()-isize;
  214. Histogram hist(256);
  215. int hist_med, hist_temp;
  216. uint hist_lower = 0;
  217. uint hist_upper = 0;
  218. const Image::Pixel* pSrc;
  219. Image::Pixel* pDst;
  220. for(int y=size; y<src.height()-isize; ++y) {
  221. hist_med = -1;
  222. hist = 0;
  223. for(int sy=-isize; sy<=isize; ++sy)
  224. for(int sx=-isize; sx<=isize; ++sx)
  225. medianNext(src(1+sx,y+sy),hist,hist_temp,hist_med,hist_lower,hist_upper,true);
  226. pDst = result->getPixelPointerXY(isize,y);
  227. *pDst = hist_med;
  228. ++pDst;
  229. for(int x=xstart; x<xend; ++x,++pSrc,++pDst) {
  230. for(int i=-isize; i<=+isize; ++i) {
  231. medianNext(src.getPixelQuick(x+isize ,y+i),hist,hist_temp,hist_med,hist_lower,hist_upper,true);
  232. medianNext(src.getPixelQuick(x-isize-1,y+i),hist,hist_temp,hist_med,hist_lower,hist_upper,false);
  233. }
  234. *pDst = hist_med;
  235. }
  236. }
  237. #endif // NICE_USELIB_IPP
  238. return result;
  239. }
  240. Image* dilate(const Image& src, Image* dst, const size_t& size)
  241. {
  242. Image* result = createResultBuffer(src, dst);
  243. copyBorder ( src, size, size, dst );
  244. #ifdef NICE_USELIB_IPP
  245. IppStatus ret;
  246. IppiPoint anchor = {(int)size, (int)size};
  247. IppiSize ROIsize = {(int)(src.width()-2*size), (int)(src.height()-2*size)};
  248. // 3x3
  249. if(size==1)
  250. ret = ippiDilate3x3_8u_C1R(src.getPixelPointerXY(anchor.x, anchor.y),
  251. src.getStepsize(),
  252. result->getPixelPointerXY(anchor.x, anchor.y),
  253. result->getStepsize(),
  254. ROIsize);
  255. else
  256. {
  257. IppiSize maskSize = {(int)(2*size+1), (int)(2*size+1)};
  258. Ipp8u *pMask = new Ipp8u[(2*size+1)*(2*size+1)];
  259. ippiSet_8u_C1R(1,pMask,2*size+1,maskSize);
  260. ret = ippiDilate_8u_C1R(src.getPixelPointerXY(anchor.x, anchor.y),
  261. src.getStepsize(),
  262. result->getPixelPointerXY(anchor.x, anchor.y),
  263. result->getStepsize(),
  264. ROIsize, pMask, maskSize, anchor);
  265. }
  266. if(ret!=ippStsNoErr)
  267. fthrow(ImageException, ippGetStatusString(ret));
  268. #else // NICE_USELIB_IPP
  269. int isize = size;
  270. int xstart = size+1;
  271. int xend = src.width()-isize;
  272. Histogram hist(256);
  273. int hist_max, hist_val;
  274. const Image::Pixel* pSrc;
  275. Image::Pixel* pDst;
  276. for(int y=size; y<src.height()-isize; ++y) {
  277. hist = 0;
  278. hist_max = std::numeric_limits<int>::min();
  279. for(int sy=-isize; sy<=isize; ++sy)
  280. for(int sx=-isize; sx<=+isize; ++sx,++pSrc) {
  281. hist_val = src.getPixelQuick(size+sx,y+sy);
  282. ++hist[hist_val];
  283. if(hist_val>hist_max)
  284. hist_max = hist_val;
  285. }
  286. pDst = result->getPixelPointerXY(isize,y);
  287. *pDst = hist_max;
  288. ++pDst;
  289. // now the rest of the line
  290. pSrc = src.getPixelPointerXY(xstart,y);
  291. for(int x=xstart; x<xend; ++x,++pSrc,++pDst)
  292. *pDst = dilateNext(src,hist,isize,hist_val,hist_max,x,y);
  293. }
  294. #endif // NICE_USELIB_IPP
  295. return result;
  296. }
  297. Image* opening(const Image& src, Image* dst, const size_t& size)
  298. {
  299. Image* temp = new Image(src.width(), src.height());
  300. temp = erode(src, temp, size);
  301. Image* result = createResultBuffer(src.width(), src.height(), dst);
  302. result = dilate(*temp, result, size);
  303. // clean up
  304. delete temp;
  305. return result;
  306. }
  307. Image* closing(const Image& src, Image* dst, const size_t& size)
  308. {
  309. Image* temp = new Image(src.width(), src.height());
  310. temp = dilate(src, temp, size);
  311. Image* result = createResultBuffer(src.width(), src.height(), dst);
  312. result = erode(*temp, result, size);
  313. // clean up
  314. delete temp;
  315. return result;
  316. }
  317. // // // // // ranking operations with a given mask // // // // //
  318. // little Helperfunction, counts the number of nonZero elements in the structureElement
  319. static inline size_t getNonZeroElements(const CharMatrix& structureElement)
  320. {
  321. size_t entries = 0;
  322. for(size_t j=0; j<structureElement.rows(); ++j)
  323. for(size_t i=0; i<structureElement.cols(); ++i)
  324. if(structureElement(j,i)!=0)
  325. ++entries;
  326. return entries;
  327. }
  328. // little Helperfunction, creates a Matrix with coordinates of nonzero Elements
  329. // referring to the center of the structureElement
  330. static inline IntMatrix* getStructureList(const CharMatrix& structureElement, IppiPoint& min, IppiPoint& max)
  331. {
  332. size_t entries = getNonZeroElements(structureElement);
  333. int anchorx = static_cast<int>(structureElement.cols()/2);
  334. int anchory = static_cast<int>(structureElement.rows()/2);
  335. min.x = std::numeric_limits<int>::max();
  336. min.y = std::numeric_limits<int>::max();
  337. max.x = std::numeric_limits<int>::min();
  338. max.y = std::numeric_limits<int>::min();
  339. IntMatrix *pRes = new IntMatrix(entries,2);
  340. size_t aPos = 0;
  341. for(size_t j=0; j<structureElement.rows(); ++j)
  342. for(size_t i=0; i<structureElement.cols(); ++i)
  343. if(structureElement(j,i)!=0) {
  344. (*pRes)(aPos,0) = i-anchorx;
  345. (*pRes)(aPos,1) = j-anchory;
  346. max.x = std::max((*pRes)(aPos,0),max.x);
  347. min.x = std::min((*pRes)(aPos,0),min.x);
  348. min.y = std::min((*pRes)(aPos,1),min.y);
  349. max.y = std::max((*pRes)(aPos,1),max.y);
  350. ++aPos;
  351. }
  352. return pRes;
  353. }
  354. Image* rank(const Image& src, const CharMatrix& structureElement, const size_t& rank, Image* dst)
  355. {
  356. Image* result = createResultBuffer(src, dst);
  357. copyBorder ( src, structureElement.cols()/2, structureElement.rows()/2, dst );
  358. size_t entries = getNonZeroElements(structureElement);
  359. if( entries==0 )
  360. fthrow(ImageException,"No Elements specified for the ranking operation.");
  361. if( rank>entries || rank<1 )
  362. fthrow(ImageException,"Rank smaller 1 or bigger than nonzero entries in the structureElement are not allowed.");
  363. Histogram hist(256);
  364. IppiPoint min,max;
  365. IntMatrix* strucList = getStructureList(structureElement, min, max);
  366. int xstart = -min.x;
  367. int xend = src.width()-max.x;
  368. int i;
  369. Image::Pixel* p;
  370. for(int y=-min.y; y<src.height()-max.y; ++y) {
  371. p = result->getPixelPointerXY(xstart,y);
  372. for(int x=xstart; x<xend; ++x,++p) {
  373. hist = 0;
  374. i = strucList->rows()-1;
  375. do {
  376. ++hist[src(x+(*strucList)(i,0), y+(*strucList)(i,1))];
  377. --i;
  378. }
  379. while(i>=0);
  380. *p = getHistRank(hist,rank);
  381. }
  382. }
  383. // clean up
  384. delete strucList;
  385. return result;
  386. };
  387. Image* median(const Image& src, const CharMatrix& structureElement, Image* dst)
  388. {
  389. Image* result = createResultBuffer(src, dst);
  390. size_t nonZero = getNonZeroElements(structureElement);
  391. return rank(src, structureElement, ((nonZero%2==0)?nonZero/2:nonZero/2+1), result);
  392. }
  393. Image* erode(const Image& src, const CharMatrix& structureElement, Image* dst)
  394. {
  395. Image* result = createResultBuffer(src, dst);
  396. copyBorder ( src, structureElement.cols()/2, structureElement.rows()/2, dst );
  397. #ifdef NICE_USELIB_IPP
  398. // temporary bugfix: do not use IPP (bug on 64bit systems)
  399. //#define NICE_USELIB_IPP_ERODE
  400. #endif
  401. #ifdef NICE_USELIB_IPP_ERODE
  402. IppiPoint anchor = {structureElement.cols()/2, structureElement.rows()/2};
  403. IppiSize maskSize = {structureElement.cols() , structureElement.rows()};
  404. IppiSize ROIsize = {src.width()-structureElement.cols()-1, src.height()-structureElement.rows()-1};
  405. MatrixT<unsigned char> sEl(structureElement.cols(), structureElement.rows());
  406. for(uint j=0; j<structureElement.rows(); ++j)
  407. for(uint i=0; i<structureElement.cols(); ++i)
  408. sEl(i,j) = (structureElement(j,i)==0)?0:1;
  409. IppStatus ret = ippiErode_8u_C1R(src.getPixelPointerXY(anchor.x,anchor.y),
  410. src.getStepsize(),
  411. result->getPixelPointerXY(anchor.x,anchor.y),
  412. result->getStepsize(),
  413. ROIsize, sEl.getDataPointer(),
  414. maskSize, anchor);
  415. if(ret!=ippStsNoErr)
  416. fthrow(ImageException, ippGetStatusString(ret));
  417. #else // NICE_USELIB_IPP_ERODE
  418. result = rank(src, structureElement, 1, dst);
  419. #endif // NICE_USELIB_IPP_ERODE
  420. return result;
  421. }
  422. Image* dilate(const Image& src, const CharMatrix& structureElement, Image* dst)
  423. {
  424. Image* result = createResultBuffer(src, dst);
  425. copyBorder ( src, structureElement.cols()/2, structureElement.rows()/2, dst );
  426. #ifdef NICE_USELIB_IPP
  427. IppiPoint anchor = {(int)(structureElement.cols()/2), (int)(structureElement.rows()/2)};
  428. IppiSize maskSize = {(int)(structureElement.cols()), (int)(structureElement.rows())};
  429. IppiSize ROIsize = {(int)(src.width()-structureElement.cols()-1), (int)(src.height()-structureElement.rows()-1)};
  430. MatrixT<unsigned char> sEl(structureElement.rows(), structureElement.cols());
  431. for(uint j=0; j<structureElement.rows(); ++j)
  432. for(uint i=0; i<structureElement.cols(); ++i)
  433. sEl(j,i) = (structureElement(j,i)==0) ? 0 : 1;
  434. // IPP seems to ignore black patches and we get a strange image
  435. // afterwards (one some machines!!) with grayvalues of 128 etc.
  436. // Fixed 15.12.2011 by erik after a TestMorph test case failed
  437. result->set(0.0);
  438. IppStatus ret = ippiDilate_8u_C1R(src.getPixelPointerXY(anchor.x,anchor.y),
  439. src.getStepsize(),
  440. result->getPixelPointerXY(anchor.x,anchor.y),
  441. result->getStepsize(),
  442. ROIsize, sEl.getDataPointer(),
  443. maskSize, anchor);
  444. if(ret!=ippStsNoErr)
  445. fthrow(ImageException, ippGetStatusString(ret));
  446. #else // NICE_USELIB_IPP
  447. result = rank(src, structureElement, getNonZeroElements(structureElement), dst);
  448. #endif // NICE_USELIB_IPP
  449. return result;
  450. }
  451. Image* opening(const Image& src, const CharMatrix& structureElement, Image* dst)
  452. {
  453. Image* temp = new Image(src.width(), src.height());
  454. temp = erode(src, structureElement, temp);
  455. Image* result = createResultBuffer(src.width(), src.height(), dst);
  456. result = dilate(*temp, structureElement, result);
  457. // clean up
  458. delete temp;
  459. return result;
  460. }
  461. Image* closing(const Image& src, const CharMatrix& structureElement, Image* dst)
  462. {
  463. Image* temp = new Image(src.width(), src.height());
  464. temp = dilate(src, structureElement, temp);
  465. Image* result = createResultBuffer(src.width(), src.height(), dst);
  466. result = erode(*temp, structureElement, result);
  467. // clean up
  468. delete temp;
  469. return result;
  470. }
  471. // // // // // IP Operations // // // // //
  472. void rankingIP(Image& src, const uint& rank)
  473. {
  474. if( rank>9 || rank<1 )
  475. fthrow(ImageException,"Rank is out of range.");
  476. Histogram hist(256);
  477. Image::Pixel* p;
  478. Ipp8u* buffer = new Ipp8u[src.width()];
  479. buffer[0] = buffer[src.width()-1] = 0;
  480. Ipp8u* temp = new Ipp8u[2];
  481. // init buffer with the first image line (y=1)
  482. hist = 0;
  483. for(int j=-1; j<=+1; ++j)
  484. for(int i=-1; i<=+1; ++i)
  485. ++hist[src(1+i,1+j)];
  486. buffer[1] = getHistRank(hist, rank);
  487. p = src.getPixelPointerXY(2,1);
  488. for(int x=2; x<src.width()-1; ++x,++p)
  489. for(int i=-1; i<=+1; ++i) {
  490. ++hist[*(p+1+i*src.getStepsize())];
  491. --hist[*(p-2+i*src.getStepsize())];
  492. buffer[x] = getHistRank(hist, rank);
  493. }
  494. for(int y=2; y<=src.height()-2; ++y) {
  495. hist = 0;
  496. for(int j=-1; j<=+1; ++j)
  497. for(int x=0; x<=2; ++x)
  498. ++hist[src(x,y+j)];
  499. temp[0] = getHistRank(hist, rank);
  500. for(int i=-1; i<=+1; ++i) {
  501. ++hist[src(3,y+i)];
  502. --hist[src(0,y+i)];
  503. }
  504. temp[1] = getHistRank(hist, rank);
  505. p = src.getPixelPointerXY(1,y-1);
  506. for(int x=3; x<=src.width()-2; ++x) {
  507. for(int i=-1; i<=+1; ++i) {
  508. ++hist[*(p+3+(i+1)*src.getStepsize())];
  509. --hist[*(p +(i+1)*src.getStepsize())];
  510. }
  511. *p++ = buffer[x-2];
  512. buffer[x-2] = temp[0];
  513. temp[0] = temp[1];
  514. temp[1] = getHistRank(hist,rank);
  515. }
  516. // write buffer
  517. *p++ = buffer[src.width()-3];
  518. *p++ = buffer[src.width()-2];
  519. buffer[src.width()-3] = temp[0];
  520. buffer[src.width()-2] = temp[1];
  521. }
  522. // copy buffer to last line
  523. memcpy(src.getPixelPointerXY(1,src.height()-2), &buffer[1], src.width()-2);
  524. // clean up
  525. delete[] buffer;
  526. delete[] temp;
  527. }
  528. void erodeIP(Image& src)
  529. {
  530. #ifdef NICE_USELIB_IPP
  531. IppiSize ROIsize = {src.width()-2, src.height()-2};
  532. IppStatus ret = ippiErode3x3_8u_C1IR(src.getPixelPointerXY(1,1), src.getStepsize(), ROIsize);
  533. if(ret!=ippStsNoErr)
  534. fthrow(ImageException, ippGetStatusString(ret));
  535. #else
  536. Histogram hist(256);
  537. int hist_min, hist_val;
  538. Image::Pixel* p;
  539. Ipp8u* buffer = new Ipp8u[src.width()];
  540. buffer[0] = buffer[src.width()-1] = 0;
  541. Ipp8u* temp = new Ipp8u[2];
  542. // init buffer with the first image line (y=1)
  543. // init hist
  544. hist = 0;
  545. hist_min = std::numeric_limits<int>::max();
  546. for(int y=0; y<=2; ++y)
  547. for(int x=0; x<=2; ++x) {
  548. hist_val = src.getPixelQuick(x,y);
  549. hist_min = (hist_val<hist_min)?hist_val:hist_min;
  550. ++hist[hist_val];
  551. }
  552. buffer[0] = buffer[src.width()-1] = 0;
  553. buffer[1] = hist_min;
  554. // init buffer
  555. for(int x=2; x<src.width()-1; ++x)
  556. buffer[x] = erodeNext(src,hist,1,hist_val,hist_min,x,1);
  557. for(int y=2; y<=src.height()-2; ++y) {
  558. // init hist && fill up temp buffer
  559. hist = 0;
  560. hist_min = std::numeric_limits<int>::max();
  561. for(int j=-1; j<=1; ++j)
  562. for(int i=-1; i<=1; ++i) {
  563. hist_val = src(1+i,y+j);
  564. hist_min = (hist_val<hist_min)?hist_val:hist_min;
  565. ++hist[hist_val];
  566. }
  567. temp[0] = hist_min;
  568. temp[1] = erodeNext(src,hist,1,hist_val,hist_min,2,y);
  569. // rest of line
  570. p = src.getPixelPointerXY(1,y-1);
  571. for(int x=3; x<=src.width()-2; ++x) {
  572. erodeNext(src,hist,1,hist_val,hist_min,x,y);
  573. *p = buffer[x-2]; ++p;
  574. buffer[x-2] = temp[0];
  575. temp[0] = temp[1];
  576. temp[1] = hist_min;
  577. }
  578. // write buffer
  579. *p = buffer[src.width()-3]; ++p;
  580. *p = buffer[src.width()-2]; ++p;
  581. buffer[src.width()-3] = temp[0];
  582. buffer[src.width()-2] = temp[1];
  583. }
  584. // copy buffer to last line
  585. memcpy(src.getPixelPointerXY(1,src.height()-2), &buffer[1], src.width()-2);
  586. // clean up
  587. delete[] buffer;
  588. delete[] temp;
  589. #endif
  590. }
  591. void medianIP(Image& src) {
  592. Histogram hist(256);
  593. int hist_med, hist_temp;
  594. uint hist_lower = 0;
  595. uint hist_upper = 0;
  596. Ipp8u* buffer = new Ipp8u[src.width()];
  597. buffer[0] = buffer[src.width()-1] = 0;
  598. Ipp8u* temp = new Ipp8u[2];
  599. Ipp8u* p;
  600. // init buffer with the first image line (y=1)
  601. // init hist
  602. hist = 0;
  603. hist_med = -1;
  604. for(int y=0; y<=2; ++y)
  605. for(int x=0; x<=2; ++x)
  606. medianNext(src.getPixelQuick(x,y),hist,hist_temp,hist_med,hist_lower,hist_upper);
  607. buffer[1] = hist_med;
  608. for(int x=2; x<src.width()-1; ++x) {
  609. for(int i=-1; i<=+1; ++i) {
  610. medianNext(src.getPixelQuick(x+1,1+i),hist,hist_temp,hist_med,hist_lower,hist_upper,true);
  611. medianNext(src.getPixelQuick(x-2,1+i),hist,hist_temp,hist_med,hist_lower,hist_upper,false);
  612. }
  613. buffer[x] = hist_med;
  614. }
  615. for(int y=2; y<=src.height()-2; ++y) {
  616. hist = 0;
  617. hist_med = -1;
  618. for(int j=-1; j<=1; ++j)
  619. for(int i=-1; i<=1; ++i,++p)
  620. medianNext(src.getPixelQuick(1+i,y+j),hist,hist_temp,hist_med,hist_lower,hist_upper,true);
  621. temp[0] = hist_med;
  622. for(int i=-1; i<=1; ++i) {
  623. medianNext(src.getPixelQuick(3,y+i),hist,hist_temp,hist_med,hist_lower,hist_upper,true);
  624. medianNext(src.getPixelQuick(0,y+i),hist,hist_temp,hist_med,hist_lower,hist_upper,false);
  625. }
  626. temp[1] = hist_med;
  627. // rest of line
  628. p = src.getPixelPointerXY(1,y-1);
  629. for(int x=3; x<=src.width()-2; ++x,++p) {
  630. for(int i=-1; i<=1; ++i) {
  631. medianNext(src.getPixelQuick(x+1,y+i),hist,hist_temp,hist_med,hist_lower,hist_upper);
  632. medianNext(src.getPixelQuick(x-2,y+i),hist,hist_temp,hist_med,hist_lower,hist_upper,false);
  633. }
  634. *p = buffer[x-2];
  635. buffer[x-2] = temp[0];
  636. temp[0] = temp[1];
  637. temp[1] = hist_med;
  638. }
  639. // write buffer
  640. *p = buffer[src.width()-3]; ++p;
  641. *p = buffer[src.width()-2]; ++p;
  642. buffer[src.width()-3] = temp[0];
  643. buffer[src.width()-2] = temp[1];
  644. }
  645. // copy buffer to last line
  646. memcpy(src.getPixelPointerXY(1,src.height()-2), &buffer[1], src.width()-2);
  647. // clean up
  648. delete[] buffer;
  649. delete[] temp;
  650. }
  651. void dilateIP(Image& src)
  652. {
  653. #ifdef NICE_USELIB_IPP
  654. IppiSize ROIsize = {src.width()-2, src.height()-2};
  655. IppStatus ret = ippiDilate3x3_8u_C1IR(src.getPixelPointerXY(1,1), src.getStepsize(), ROIsize);
  656. if(ret!=ippStsNoErr)
  657. fthrow(ImageException, ippGetStatusString(ret));
  658. #else
  659. Histogram hist(256);
  660. int hist_max, hist_val;
  661. Ipp8u* p;
  662. Ipp8u* buffer = new Ipp8u[src.width()];
  663. buffer[0] = buffer[src.width()-1] = 0;
  664. Ipp8u* temp = new Ipp8u[2];
  665. // init buffer with the first image line (y=1)
  666. // init hist
  667. hist = 0;
  668. hist_max = std::numeric_limits<int>::min();
  669. for(int y=0; y<=2; ++y)
  670. for(int x=0; x<=2; ++x) {
  671. hist_val = src(x,y);
  672. if(hist_val>hist_max)
  673. hist_max = hist_val;
  674. ++hist[hist_val];
  675. }
  676. buffer[1] = hist_max;
  677. // init buffer
  678. for(int x=2; x<src.width()-1; ++x)
  679. buffer[x] = dilateNext(src,hist,1,hist_val,hist_max,x,1);
  680. for(int y=2; y<=src.height()-2; ++y) {
  681. // init hist && fill up temp buffer
  682. hist = 0;
  683. hist_max = std::numeric_limits<int>::min();
  684. for(int j=-1; j<=1; ++j)
  685. for(int i=-1; i<=1; ++i) {
  686. hist_val = src(1+i,y+j);
  687. if(hist_val>hist_max)
  688. hist_max = hist_val;
  689. ++hist[hist_val];
  690. }
  691. temp[0] = hist_max;
  692. temp[1] = dilateNext(src,hist,1,hist_val,hist_max,2,y);
  693. // rest of line
  694. p = src.getPixelPointerXY(1,y-1);
  695. for(int x=3; x<=src.width()-2; ++x) {
  696. dilateNext(src,hist,1,hist_val,hist_max,x,y);
  697. *p = buffer[x-2]; ++p;
  698. buffer[x-2] = temp[0];
  699. temp[0] = temp[1];
  700. temp[1] = hist_max;
  701. }
  702. // write buffer
  703. *p = buffer[src.width()-3]; ++p;
  704. *p = buffer[src.width()-2]; ++p;
  705. buffer[src.width()-3] = temp[0];
  706. buffer[src.width()-2] = temp[1];
  707. }
  708. // copy buffer to last line
  709. memcpy(src.getPixelPointerXY(1,src.height()-2), &buffer[1], src.width()-2);
  710. // clean up
  711. delete[] buffer;
  712. delete[] temp;
  713. #endif
  714. }
  715. void openingIP(Image& src)
  716. {
  717. erodeIP(src);
  718. dilateIP(src);
  719. }
  720. void closingIP(Image& src)
  721. {
  722. dilateIP(src);
  723. erodeIP(src);
  724. }
  725. // // // // // Matching Operations // // // // //
  726. Image* hitAndMiss(const Image& src, const CharMatrix& structureElement, Image* dst)
  727. {
  728. Image* result = createResultBuffer(src, dst);
  729. Image* temp = erode(src, structureElement);
  730. // invert the structure element and source image
  731. CharMatrix* invStructure = new CharMatrix(structureElement.rows(), structureElement.cols());
  732. for(size_t j=0; j<structureElement.rows(); ++j)
  733. for(size_t i=0; i<structureElement.cols(); ++i)
  734. (*invStructure)(j,i) = (structureElement(j,i)==0)?1:0;
  735. // invert the source image
  736. Image* invSrc = new Image(src);
  737. invSrc->invert();
  738. result = erode(*invSrc, *invStructure);
  739. // do an and-combination
  740. const Image::Pixel *pSrc;
  741. Image::Pixel *pDst;
  742. for(int y=0; y<result->height(); ++y) {
  743. pSrc = temp->getPixelPointerY(y);
  744. pDst = result->getPixelPointerY(y);
  745. for(int x=0; x<result->width(); ++x,++pSrc,++pDst)
  746. *pDst = (*pSrc==*pDst && *pSrc!=0)?255:0;
  747. }
  748. // cleanUp
  749. delete invStructure;
  750. delete invSrc;
  751. delete temp;
  752. return result;
  753. }
  754. } // namespace NICE