Convert.tcc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include "core/image/Convert.h"
  2. #include <iostream>
  3. #include <limits>
  4. #include "core/image/ColorImageT.h"
  5. #include <core/basics/tools.h>
  6. namespace NICE {
  7. template<class P>
  8. ImageT<P>* rgbToGray(const ColorImageT<P>& src, ImageT<P>* dst,
  9. const ImageT<int>* rgbToGrayLUT)
  10. {
  11. ImageT<P>* result = createResultBuffer(src.width(), src.height(), dst);
  12. #ifdef NICE_USELIB_IPP
  13. UNUSED_PARAMETER(rgbToGrayLUT);
  14. IppStatus ret = ippiRGBToGray_C3C1R(src.getPixelPointer(), src.getStepsize(),
  15. result->getPixelPointer(), result->getStepsize(),
  16. makeROIFullImage(src));
  17. if(ret!=ippStsNoErr)
  18. fthrow(ImageException, ippGetStatusString(ret));
  19. #else // NICE_USELIB_IPP
  20. const P *pSrc;
  21. P *pDst;
  22. // use lut if given
  23. if(sizeof(P)==1 && rgbToGrayLUT!=NULL)
  24. for(int y=0; y<result->height(); ++y) {
  25. pSrc = src.getPixelPointerY(y);
  26. pDst = result->getPixelPointerY(y);
  27. for (int x=0; x<result->width(); ++x,pSrc+=3,++pDst)
  28. *pDst = static_cast<P>( rgbToGrayLUT->getPixelQuick(static_cast<int>(*pSrc),0) +
  29. rgbToGrayLUT->getPixelQuick(static_cast<int>(*(pSrc+1)),1) +
  30. rgbToGrayLUT->getPixelQuick(static_cast<int>(*(pSrc+2)),2) );
  31. }
  32. // else calculate values
  33. else
  34. for(int y=0; y<result->height(); ++y) {
  35. pSrc = src.getPixelPointerY(y);
  36. pDst = result->getPixelPointerY(y);
  37. for(int i=0; i<result->width(); ++i,pSrc+=3,++pDst)
  38. *pDst = static_cast<P>(*pSrc*0.299+*(pSrc+1)*0.587+*(pSrc+2)*0.114);
  39. }
  40. #endif // NICE_USELIB_IPP
  41. return result;
  42. }
  43. template<class P>
  44. ColorImageT<P>* grayToRGB(const ImageT<P>& src, ColorImageT<P>* dst)
  45. {
  46. ColorImageT<P>* result = createResultBuffer(src.width(), src.height(), dst);
  47. #ifdef NICE_USELIB_IPP
  48. const P* buf[3];
  49. for(int i=0; i<=2; ++i)
  50. buf[i] = src.getPixelPointer();
  51. IppStatus ret = ippiCopy_P3C3R(buf, src.getStepsize(),
  52. result->getPixelPointer(), result->getStepsize(),
  53. makeROIFullImage(src));
  54. if(ret!=ippStsNoErr)
  55. fthrow(ImageException, ippGetStatusString(ret));
  56. #else // NICE_USELIB_IPP
  57. int i;
  58. const P* pSrcStart = src.getPixelPointer();
  59. P* pDstStart = result->getPixelPointer();
  60. // FIXME only works if getStepsize() is a multiple of sizeof(P)
  61. // (same problem probably in many other functions)
  62. // however, without IPP, this is usually ok (no guarantees, however)
  63. int sStep = src.getStepsize()/sizeof(P);
  64. int dStep = result->getStepsize()/sizeof(Ipp32f);
  65. const P* pSrc;
  66. P* pDst;
  67. for (int y=0; y<result->height(); ++y) {
  68. pSrc = pSrcStart;
  69. pDst = pDstStart;
  70. for (int x=0; x<result->width(); ++x,++pSrc) {
  71. i=3;
  72. do {
  73. *pDst = *pSrc;
  74. ++pDst;
  75. --i;
  76. } while(i!=0);
  77. }
  78. pSrcStart += sStep;
  79. pDstStart += dStep;
  80. }
  81. #endif // NICE_USELIB_IPP
  82. return(result);
  83. }
  84. template<class P>
  85. void matrixToPseudoColor ( const NICE::MatrixT<P> & m, NICE::ColorImage & img )
  86. {
  87. img.resize ( m.cols(), m.rows() );
  88. double max = - std::numeric_limits<double>::max();
  89. double min = std::numeric_limits<double>::max();
  90. for ( size_t x = 0 ; x < ( size_t ) m.cols(); x++ )
  91. for ( size_t y = 0 ; y < ( size_t ) m.rows() ; y++ )
  92. {
  93. if ( m ( y, x ) > max ) max = m ( y, x );
  94. if ( m ( y, x ) < min ) min = m ( y, x );
  95. }
  96. for ( size_t y = 0 ; y < ( size_t ) m.rows() ; y++ )
  97. for ( size_t x = 0 ; x < ( size_t ) m.cols(); x++ )
  98. {
  99. double val = ( m ( y, x ) - min ) / ( max - min );
  100. double r, g, b;
  101. convertToPseudoColor ( val, r, g, b );
  102. img.setPixel ( x, y, 0, ( int ) ( r*255 ) );
  103. img.setPixel ( x, y, 1, ( int ) ( g*255 ) );
  104. img.setPixel ( x, y, 2, ( int ) ( b*255 ) );
  105. }
  106. }
  107. template<class P>
  108. void imageToPseudoColor ( const NICE::ImageT<P> & src, NICE::ColorImage & img )
  109. {
  110. img.resize ( src.width(), src.height() );
  111. // determine maximum and minimum value in the source image
  112. // for appropiate scaling
  113. double max = - std::numeric_limits<double>::max();
  114. double min = std::numeric_limits<double>::max();
  115. for ( size_t x = 0 ; x < ( size_t ) src.width(); x++ )
  116. for ( size_t y = 0 ; y < ( size_t ) src.height() ; y++ )
  117. {
  118. double v = src.getPixel ( x, y );
  119. if ( v > max ) max = v;
  120. if ( v < min ) min = v;
  121. }
  122. for ( size_t y = 0 ; y < ( size_t ) src.height() ; y++ )
  123. for ( size_t x = 0 ; x < ( size_t ) src.width(); x++ )
  124. {
  125. // scale the grayvalue
  126. double val = ( src.getPixel ( x, y ) - min ) / ( max - min );
  127. double r, g, b;
  128. // determine the RGB values
  129. convertToPseudoColor ( val, r, g, b );
  130. img.setPixel ( x, y, 0, ( int ) ( r*255 ) );
  131. img.setPixel ( x, y, 1, ( int ) ( g*255 ) );
  132. img.setPixel ( x, y, 2, ( int ) ( b*255 ) );
  133. }
  134. }
  135. template<class P>
  136. void imageToPseudoColorWithRangeSpecification ( const NICE::ImageT<P> & src, NICE::ColorImage & img, const double & _min, const double & _max )
  137. {
  138. img.resize ( src.width(), src.height() );
  139. double max ( _max );
  140. double min ( _min );
  141. //consistency check
  142. if (max < min )
  143. {
  144. min = max;
  145. max = _min;
  146. }
  147. //to avoid division by numerical zero
  148. double rangeSpecified ( fabs(max - min) );
  149. if ( rangeSpecified < 10e-10 )
  150. {
  151. max = min + 10e-10;
  152. rangeSpecified = fabs(max - min);
  153. }
  154. for ( size_t y = 0 ; y < ( size_t ) src.height() ; y++ )
  155. for ( size_t x = 0 ; x < ( size_t ) src.width(); x++ )
  156. {
  157. // scale the grayvalue
  158. double val = ( src.getPixel ( x, y ) - min );
  159. val = std::max( val , min ); // check for lower bound
  160. val = std::min( val , max ); //check for upper bound
  161. val /= rangeSpecified; //appropriate scaling
  162. double r, g, b;
  163. // determine the RGB values
  164. convertToPseudoColor ( val, r, g, b );
  165. img.setPixel ( x, y, 0, ( int ) ( r*255 ) );
  166. img.setPixel ( x, y, 1, ( int ) ( g*255 ) );
  167. img.setPixel ( x, y, 2, ( int ) ( b*255 ) );
  168. }
  169. }
  170. template<class P>
  171. FloatImage* grayToFloat(const ImageT<P>& src, FloatImage* dst)
  172. {
  173. FloatImage* result = createResultBuffer(src.width(), src.height(), dst);
  174. #ifdef NICE_USELIB_IPP
  175. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  176. result->getPixelPointer(), result->getStepsize(),
  177. makeROIFullImage(src));
  178. if(ret!=ippStsNoErr)
  179. fthrow(ImageException, ippGetStatusString(ret));
  180. #else
  181. const P* pSrcStart = src.getPixelPointer();
  182. Ipp32f* pDstStart = result->getPixelPointer();
  183. int sStep = src.getStepsize()/sizeof(P);
  184. int dStep = result->getStepsize()/sizeof(Ipp32f);
  185. const P *pSrc;
  186. FloatImage::Pixel *pDst;
  187. for(int y=0; y<src.height(); ++y) {
  188. pSrc = pSrcStart;
  189. pDst = pDstStart;
  190. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  191. *pDst = *pSrc;
  192. pSrcStart += sStep;
  193. pDstStart += dStep;
  194. }
  195. #endif // NICE_USELIB_IPP
  196. return result;
  197. }
  198. template<class P>
  199. ImageT<P>* floatToGray(const FloatImage& src, ImageT<P>* dst, IppRoundMode roundMode)
  200. {
  201. ImageT<P>* result = createResultBuffer(src, dst);
  202. #ifdef NICE_USELIB_IPP
  203. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  204. result->getPixelPointer(), result->getStepsize(),
  205. makeROIFullImage(src), roundMode);
  206. if(ret!=ippStsNoErr)
  207. fthrow(ImageException, ippGetStatusString(ret));
  208. #else
  209. const Ipp32f* pSrcStart = src.getPixelPointer();
  210. P* pDstStart = result->getPixelPointer();
  211. int sStep = src.getStepsize()/sizeof(Ipp32f);
  212. int dStep = result->getStepsize()/sizeof(P);
  213. const Ipp32f* pSrc;
  214. P* pDst;
  215. for(int y=0; y<src.height(); ++y) {
  216. pSrc = pSrcStart;
  217. pDst = pDstStart;
  218. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  219. if(*pSrc < std::numeric_limits<P>::min())
  220. *pDst = std::numeric_limits<P>::min();
  221. else if(*pSrc > std::numeric_limits<P>::max())
  222. *pDst = std::numeric_limits<P>::max();
  223. else
  224. if(roundMode == ippRndZero)
  225. *pDst = static_cast<P>(*pSrc);
  226. else
  227. *pDst = static_cast<P>(round(*pSrc));
  228. pSrcStart += sStep;
  229. pDstStart += dStep;
  230. }
  231. #endif // NICE_USELIB_IPP
  232. return result;
  233. }
  234. // bitdepth conversion without scaling
  235. template<class P1, class P2>
  236. ImageT<P2>* convertBitDepth(const ImageT<P1>& src, ImageT<P2>* dst)
  237. {
  238. ImageT<P2>* result = createResultBuffer(src.width(), src.height(), dst);
  239. #ifdef NICE_USELIB_IPP
  240. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  241. result->getPixelPointer(), result->getStepsize(),
  242. makeROIFullImage(src));
  243. if(ret!=ippStsNoErr)
  244. fthrow(ImageException, ippGetStatusString(ret));
  245. #else // NICE_USELIB_IPP
  246. const P1* pSrc;
  247. P2* pDst;
  248. if(sizeof(P1)<sizeof(P2))
  249. for(int y=0; y<src.height(); ++y) {
  250. pSrc = src.getPixelPointerY(y);
  251. pDst = result->getPixelPointerY(y);
  252. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  253. *pDst = static_cast<P2>(*pSrc);
  254. }
  255. else
  256. for(int y=0; y<src.height(); ++y) {
  257. pSrc = src.getPixelPointerY(y);
  258. pDst = result->getPixelPointerY(y);
  259. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  260. if(*pSrc < std::numeric_limits<P2>::min())
  261. *pDst = std::numeric_limits<P2>::min();
  262. else if(*pSrc > std::numeric_limits<P2>::max())
  263. *pDst = std::numeric_limits<P2>::max();
  264. else
  265. *pDst = static_cast<P2>(round(*pSrc));
  266. }
  267. #endif // NICE_USELIB_IPP
  268. return result;
  269. }
  270. // specialication for convertBitDepth to decrease bitdepth from 32f to 8u/8s/16u/16s
  271. template<class P>
  272. ImageT<P>* convertBitDepth(const ImageT<Ipp32f>& src, ImageT<P>* dst)
  273. {
  274. ImageT<P>* result = createResultBuffer(src.width(), src.height(), dst);
  275. #ifdef NICE_USELIB_IPP
  276. if(sizeof(Ipp32f)<sizeof(P))
  277. fthrow(ImageException,"Conversion not supported by IPP.");
  278. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  279. result->getPixelPointer(), result->getStepsize(),
  280. makeROIFullImage(src), ippRndNear);
  281. if(ret!=ippStsNoErr)
  282. fthrow(ImageException, ippGetStatusString(ret));
  283. #else // NICE_USELIB_IPP
  284. const FloatImage::Pixel* pSrc;
  285. P* pDst;
  286. if(sizeof(Ipp32f)<sizeof(P))
  287. for(int y=0; y<src.height(); ++y) {
  288. pSrc = src.getPixelPointerY(y);
  289. pDst = result->getPixelPointerY(y);
  290. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  291. *pDst = static_cast<P>(*pSrc);
  292. }
  293. else
  294. for(int y=0; y<src.height(); ++y) {
  295. pSrc = src.getPixelPointerY(y);
  296. pDst = result->getPixelPointerY(y);
  297. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  298. if(*pSrc < std::numeric_limits<P>::min())
  299. *pDst = std::numeric_limits<P>::min();
  300. else if(*pSrc > std::numeric_limits<P>::max())
  301. *pDst = std::numeric_limits<P>::max();
  302. else
  303. *pDst = static_cast<P>(round(*pSrc));
  304. }
  305. #endif // NICE_USELIB_IPP
  306. return result;
  307. }
  308. // bitdepth conversion without scaling
  309. template<class P1, class P2>
  310. ColorImageT<P2>* convertBitDepth(const ColorImageT<P1>& src, ColorImageT<P2>* dst)
  311. {
  312. ColorImageT<P2>* result = createResultBuffer(src.width(), src.height(), dst);
  313. #ifdef NICE_USELIB_IPP
  314. IppStatus ret = ippiConvert_C3R(src.getPixelPointer(), src.getStepsize(),
  315. result->getPixelPointer(), result->getStepsize(),
  316. makeROIFullImage(src));
  317. if(ret!=ippStsNoErr)
  318. fthrow(ImageException, ippGetStatusString(ret));
  319. #else // NICE_USELIB_IPP
  320. const P1* pSrc;
  321. P2* pDst;
  322. if(sizeof(P1)<sizeof(P2))
  323. for(int y=0; y<src.height(); ++y) {
  324. pSrc = src.getPixelPointerY(y);
  325. pDst = result->getPixelPointerY(y);
  326. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  327. *pDst = static_cast<P2>(*pSrc);
  328. }
  329. else
  330. for(int y=0; y<src.height(); ++y) {
  331. pSrc = src.getPixelPointerY(y);
  332. pDst = result->getPixelPointerY(y);
  333. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  334. if(*pSrc < std::numeric_limits<P2>::min())
  335. *pDst = std::numeric_limits<P2>::min();
  336. else if(*pSrc > std::numeric_limits<P2>::max())
  337. *pDst = std::numeric_limits<P2>::max();
  338. else
  339. *pDst = static_cast<P2>(round(*pSrc));
  340. }
  341. #endif // NICE_USELIB_IPP
  342. return result;
  343. }
  344. // specialication for convertBitDepth to decrease bitdepth from 32f to 8u/8s/16u/16s
  345. template<class P>
  346. ColorImageT<P>* convertBitDepth(const ColorImageT<Ipp32f> &src, ColorImageT<P>* dst)
  347. {
  348. ColorImageT<P>* result = createResultBuffer(src.width(), src.height(), dst);
  349. #ifdef NICE_USELIB_IPP
  350. if(sizeof(Ipp32f)<sizeof(P))
  351. fthrow(ImageException,"Conversion not supported by IPP.");
  352. IppStatus ret = ippiConvert_C3R(src.getPixelPointer(), src.getStepsize(),
  353. result->getPixelPointer(), result->getStepsize(),
  354. makeROIFullImage(src), ippRndNear);
  355. if(ret!=ippStsNoErr)
  356. fthrow(ImageException, ippGetStatusString(ret));
  357. #else // NICE_USELIB_IPP
  358. const Ipp32f* pSrc;
  359. P* pDst;
  360. if(sizeof(Ipp32f)<sizeof(P))
  361. for(int y=0; y<src.height(); ++y) {
  362. pSrc = src.getPixelPointerY(y);
  363. pDst = result->getPixelPointerY(y);
  364. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  365. *pDst = static_cast<P>(*pSrc);
  366. }
  367. else
  368. for(int y=0; y<src.height(); ++y) {
  369. pSrc = src.getPixelPointerY(y);
  370. pDst = result->getPixelPointerY(y);
  371. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  372. if(*pSrc < std::numeric_limits<P>::min())
  373. *pDst = std::numeric_limits<P>::min();
  374. else if(*pSrc > std::numeric_limits<P>::max())
  375. *pDst = std::numeric_limits<P>::max();
  376. else
  377. *pDst = static_cast<P>(round(*pSrc));
  378. }
  379. #endif // NICE_USELIB_IPP
  380. return result;
  381. }
  382. template<class P>
  383. ImageT<P>* scale(const ImageT<P>& src, ImageT<P>* dst, double xFactor, double yFactor, int interpolation)
  384. {
  385. #ifdef NICE_USELIB_IPP
  386. IppiRect rect = makeRectFullImage(src);
  387. IppiSize dstSize;
  388. if(isZero(xFactor) && dst!=NULL) {
  389. dstSize.width = dst->width();
  390. xFactor=dst->width()/(double)src.width();
  391. } else
  392. dstSize.width = (int) ceil ((double) src.width () * xFactor);
  393. if(isZero(yFactor) && dst!=NULL) {
  394. dstSize.height = dst->height();
  395. yFactor=dst->height()/(double)src.height();
  396. } else
  397. dstSize.height = (int) ceil ((double)src.height () * yFactor);
  398. ImageT<P> * result = createResultBuffer(dstSize.width, dstSize.height, dst);
  399. IppStatus ret = ippiResize_C1R(src.getPixelPointer(), makeROIFullImage(src), src.getStepsize(), rect,
  400. result->getPixelPointer(), result->getStepsize(),
  401. dstSize, xFactor, yFactor, interpolation);
  402. if(ret!=ippStsNoErr)
  403. fthrow(ImageException, ippGetStatusString(ret));
  404. return result;
  405. #else // NICE_USELIB_IPP
  406. fthrow(ImageException,"Not yet supported without IPP.");
  407. #endif // NICE_USELIB_IPP
  408. }
  409. template<class P>
  410. ColorImageT<P>* scale(const ColorImageT<P>& src, ColorImageT<P>* dst, double xFactor, double yFactor, int interpolation)
  411. {
  412. #ifdef NICE_USELIB_IPP
  413. IppiRect rect = makeRectFullImage(src);
  414. IppiSize dstSize;
  415. if(isZero(xFactor) && dst!=NULL) {
  416. dstSize.width = dst->width();
  417. xFactor=dst->width()/(double)src.width();
  418. } else
  419. dstSize.width = (int) ceil ((double) src.width () * xFactor);
  420. if(isZero(yFactor) && dst!=NULL) {
  421. dstSize.height = dst->height();
  422. yFactor=dst->height()/(double)src.height();
  423. } else
  424. dstSize.height = (int) ceil ((double)src.height () * yFactor);
  425. ColorImageT<P> * result = createResultBuffer(dstSize.width, dstSize.height, dst);
  426. IppStatus ret = ippiResize_C3R(src.getPixelPointer(), makeROIFullImage(src), src.getStepsize(), rect,
  427. result->getPixelPointer(), result->getStepsize(), dstSize,
  428. xFactor, yFactor, interpolation);
  429. if(ret!=ippStsNoErr)
  430. fthrow(ImageException, ippGetStatusString(ret));
  431. return result;
  432. #else // NICE_USELIB_IPP
  433. fthrow(ImageException,"Not yet supported without IPP.");
  434. #endif // NICE_USELIB_IPP
  435. }
  436. template<class P>
  437. ColorImageT<Ipp8u>* signedImageToRGB(const ImageT<P>& image,
  438. ColorImageT<Ipp8u>* colored) {
  439. //fthrow(ImageException, "signedImageToRGB() not supported for this pixel type");
  440. ColorImageT<Ipp8u> *result = createResultBuffer(image, colored);
  441. P vmin;
  442. P vmax;
  443. image.minmax(vmin, vmax);
  444. const P scale = std::max(vmax, static_cast<P>(-vmin));
  445. const Ipp8u black[3] = {0,0,0};
  446. *result = black;
  447. if (vmax == 0) {
  448. return result;
  449. }
  450. // FIXME not efficient
  451. for (int y = 0; y < image.height(); y++) {
  452. for (int x = 0; x < image.width(); x++) {
  453. const P pixel = image.getPixel(x, y);
  454. if (pixel < P(0)) {
  455. const Ipp8u newPixel = static_cast<Ipp8u>(-pixel * P(255) / scale);
  456. (*result)(x,y,0) = newPixel;
  457. } else {
  458. const Ipp8u newPixel = static_cast<Ipp8u>(pixel * P(255) / scale);
  459. (*result)(x,y,0) = newPixel;
  460. (*result)(x,y,1) = newPixel;
  461. (*result)(x,y,2) = newPixel;
  462. }
  463. }
  464. }
  465. return result;
  466. }
  467. } // namespace