Convert.tcc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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> & m, NICE::ColorImage & img )
  109. {
  110. img.resize ( m.width(), m.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 ) m.width(); x++ )
  116. for ( size_t y = 0 ; y < ( size_t ) m.height() ; y++ )
  117. {
  118. double v = m.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 ) m.height() ; y++ )
  123. for ( size_t x = 0 ; x < ( size_t ) m.width(); x++ )
  124. {
  125. // scale the grayvalue
  126. double val = ( m.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. FloatImage* grayToFloat(const ImageT<P>& src, FloatImage* dst)
  137. {
  138. FloatImage* result = createResultBuffer(src.width(), src.height(), dst);
  139. #ifdef NICE_USELIB_IPP
  140. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  141. result->getPixelPointer(), result->getStepsize(),
  142. makeROIFullImage(src));
  143. if(ret!=ippStsNoErr)
  144. fthrow(ImageException, ippGetStatusString(ret));
  145. #else
  146. const P* pSrcStart = src.getPixelPointer();
  147. Ipp32f* pDstStart = result->getPixelPointer();
  148. int sStep = src.getStepsize()/sizeof(P);
  149. int dStep = result->getStepsize()/sizeof(Ipp32f);
  150. const P *pSrc;
  151. FloatImage::Pixel *pDst;
  152. for(int y=0; y<src.height(); ++y) {
  153. pSrc = pSrcStart;
  154. pDst = pDstStart;
  155. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  156. *pDst = *pSrc;
  157. pSrcStart += sStep;
  158. pDstStart += dStep;
  159. }
  160. #endif // NICE_USELIB_IPP
  161. return result;
  162. }
  163. template<class P>
  164. ImageT<P>* floatToGray(const FloatImage& src, ImageT<P>* dst, IppRoundMode roundMode)
  165. {
  166. ImageT<P>* result = createResultBuffer(src, dst);
  167. #ifdef NICE_USELIB_IPP
  168. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  169. result->getPixelPointer(), result->getStepsize(),
  170. makeROIFullImage(src), roundMode);
  171. if(ret!=ippStsNoErr)
  172. fthrow(ImageException, ippGetStatusString(ret));
  173. #else
  174. const Ipp32f* pSrcStart = src.getPixelPointer();
  175. P* pDstStart = result->getPixelPointer();
  176. int sStep = src.getStepsize()/sizeof(Ipp32f);
  177. int dStep = result->getStepsize()/sizeof(P);
  178. const Ipp32f* pSrc;
  179. P* pDst;
  180. for(int y=0; y<src.height(); ++y) {
  181. pSrc = pSrcStart;
  182. pDst = pDstStart;
  183. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  184. if(*pSrc < std::numeric_limits<P>::min())
  185. *pDst = std::numeric_limits<P>::min();
  186. else if(*pSrc > std::numeric_limits<P>::max())
  187. *pDst = std::numeric_limits<P>::max();
  188. else
  189. if(roundMode == ippRndZero)
  190. *pDst = static_cast<P>(*pSrc);
  191. else
  192. *pDst = static_cast<P>(round(*pSrc));
  193. pSrcStart += sStep;
  194. pDstStart += dStep;
  195. }
  196. #endif // NICE_USELIB_IPP
  197. return result;
  198. }
  199. // bitdepth conversion without scaling
  200. template<class P1, class P2>
  201. ImageT<P2>* convertBitDepth(const ImageT<P1>& src, ImageT<P2>* dst)
  202. {
  203. ImageT<P2>* result = createResultBuffer(src.width(), src.height(), dst);
  204. #ifdef NICE_USELIB_IPP
  205. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  206. result->getPixelPointer(), result->getStepsize(),
  207. makeROIFullImage(src));
  208. if(ret!=ippStsNoErr)
  209. fthrow(ImageException, ippGetStatusString(ret));
  210. #else // NICE_USELIB_IPP
  211. const P1* pSrc;
  212. P2* pDst;
  213. if(sizeof(P1)<sizeof(P2))
  214. for(int y=0; y<src.height(); ++y) {
  215. pSrc = src.getPixelPointerY(y);
  216. pDst = result->getPixelPointerY(y);
  217. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  218. *pDst = static_cast<P2>(*pSrc);
  219. }
  220. else
  221. for(int y=0; y<src.height(); ++y) {
  222. pSrc = src.getPixelPointerY(y);
  223. pDst = result->getPixelPointerY(y);
  224. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  225. if(*pSrc < std::numeric_limits<P2>::min())
  226. *pDst = std::numeric_limits<P2>::min();
  227. else if(*pSrc > std::numeric_limits<P2>::max())
  228. *pDst = std::numeric_limits<P2>::max();
  229. else
  230. *pDst = static_cast<P2>(round(*pSrc));
  231. }
  232. #endif // NICE_USELIB_IPP
  233. return result;
  234. }
  235. // specialication for convertBitDepth to decrease bitdepth from 32f to 8u/8s/16u/16s
  236. template<class P>
  237. ImageT<P>* convertBitDepth(const ImageT<Ipp32f>& src, ImageT<P>* dst)
  238. {
  239. ImageT<P>* result = createResultBuffer(src.width(), src.height(), dst);
  240. #ifdef NICE_USELIB_IPP
  241. if(sizeof(Ipp32f)<sizeof(P))
  242. fthrow(ImageException,"Conversion not supported by IPP.");
  243. IppStatus ret = ippiConvert_C1R(src.getPixelPointer(), src.getStepsize(),
  244. result->getPixelPointer(), result->getStepsize(),
  245. makeROIFullImage(src), ippRndNear);
  246. if(ret!=ippStsNoErr)
  247. fthrow(ImageException, ippGetStatusString(ret));
  248. #else // NICE_USELIB_IPP
  249. const FloatImage::Pixel* pSrc;
  250. P* pDst;
  251. if(sizeof(Ipp32f)<sizeof(P))
  252. for(int y=0; y<src.height(); ++y) {
  253. pSrc = src.getPixelPointerY(y);
  254. pDst = result->getPixelPointerY(y);
  255. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  256. *pDst = static_cast<P>(*pSrc);
  257. }
  258. else
  259. for(int y=0; y<src.height(); ++y) {
  260. pSrc = src.getPixelPointerY(y);
  261. pDst = result->getPixelPointerY(y);
  262. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  263. if(*pSrc < std::numeric_limits<P>::min())
  264. *pDst = std::numeric_limits<P>::min();
  265. else if(*pSrc > std::numeric_limits<P>::max())
  266. *pDst = std::numeric_limits<P>::max();
  267. else
  268. *pDst = static_cast<P>(round(*pSrc));
  269. }
  270. #endif // NICE_USELIB_IPP
  271. return result;
  272. }
  273. // bitdepth conversion without scaling
  274. template<class P1, class P2>
  275. ColorImageT<P2>* convertBitDepth(const ColorImageT<P1>& src, ColorImageT<P2>* dst)
  276. {
  277. ColorImageT<P2>* result = createResultBuffer(src.width(), src.height(), dst);
  278. #ifdef NICE_USELIB_IPP
  279. IppStatus ret = ippiConvert_C3R(src.getPixelPointer(), src.getStepsize(),
  280. result->getPixelPointer(), result->getStepsize(),
  281. makeROIFullImage(src));
  282. if(ret!=ippStsNoErr)
  283. fthrow(ImageException, ippGetStatusString(ret));
  284. #else // NICE_USELIB_IPP
  285. const P1* pSrc;
  286. P2* pDst;
  287. if(sizeof(P1)<sizeof(P2))
  288. for(int y=0; y<src.height(); ++y) {
  289. pSrc = src.getPixelPointerY(y);
  290. pDst = result->getPixelPointerY(y);
  291. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  292. *pDst = static_cast<P2>(*pSrc);
  293. }
  294. else
  295. for(int y=0; y<src.height(); ++y) {
  296. pSrc = src.getPixelPointerY(y);
  297. pDst = result->getPixelPointerY(y);
  298. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  299. if(*pSrc < std::numeric_limits<P2>::min())
  300. *pDst = std::numeric_limits<P2>::min();
  301. else if(*pSrc > std::numeric_limits<P2>::max())
  302. *pDst = std::numeric_limits<P2>::max();
  303. else
  304. *pDst = static_cast<P2>(round(*pSrc));
  305. }
  306. #endif // NICE_USELIB_IPP
  307. return result;
  308. }
  309. // specialication for convertBitDepth to decrease bitdepth from 32f to 8u/8s/16u/16s
  310. template<class P>
  311. ColorImageT<P>* convertBitDepth(const ColorImageT<Ipp32f> &src, ColorImageT<P>* dst)
  312. {
  313. ColorImageT<P>* result = createResultBuffer(src.width(), src.height(), dst);
  314. #ifdef NICE_USELIB_IPP
  315. if(sizeof(Ipp32f)<sizeof(P))
  316. fthrow(ImageException,"Conversion not supported by IPP.");
  317. IppStatus ret = ippiConvert_C3R(src.getPixelPointer(), src.getStepsize(),
  318. result->getPixelPointer(), result->getStepsize(),
  319. makeROIFullImage(src), ippRndNear);
  320. if(ret!=ippStsNoErr)
  321. fthrow(ImageException, ippGetStatusString(ret));
  322. #else // NICE_USELIB_IPP
  323. const Ipp32f* pSrc;
  324. P* pDst;
  325. if(sizeof(Ipp32f)<sizeof(P))
  326. for(int y=0; y<src.height(); ++y) {
  327. pSrc = src.getPixelPointerY(y);
  328. pDst = result->getPixelPointerY(y);
  329. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  330. *pDst = static_cast<P>(*pSrc);
  331. }
  332. else
  333. for(int y=0; y<src.height(); ++y) {
  334. pSrc = src.getPixelPointerY(y);
  335. pDst = result->getPixelPointerY(y);
  336. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  337. if(*pSrc < std::numeric_limits<P>::min())
  338. *pDst = std::numeric_limits<P>::min();
  339. else if(*pSrc > std::numeric_limits<P>::max())
  340. *pDst = std::numeric_limits<P>::max();
  341. else
  342. *pDst = static_cast<P>(round(*pSrc));
  343. }
  344. #endif // NICE_USELIB_IPP
  345. return result;
  346. }
  347. template<class P>
  348. ImageT<P>* scale(const ImageT<P>& src, ImageT<P>* dst, double xFactor, double yFactor, int interpolation)
  349. {
  350. #ifdef NICE_USELIB_IPP
  351. IppiRect rect = makeRectFullImage(src);
  352. IppiSize dstSize;
  353. if(isZero(xFactor) && dst!=NULL) {
  354. dstSize.width = dst->width();
  355. xFactor=dst->width()/(double)src.width();
  356. } else
  357. dstSize.width = (int) ceil ((double) src.width () * xFactor);
  358. if(isZero(yFactor) && dst!=NULL) {
  359. dstSize.height = dst->height();
  360. yFactor=dst->height()/(double)src.height();
  361. } else
  362. dstSize.height = (int) ceil ((double)src.height () * yFactor);
  363. ImageT<P> * result = createResultBuffer(dstSize.width, dstSize.height, dst);
  364. IppStatus ret = ippiResize_C1R(src.getPixelPointer(), makeROIFullImage(src), src.getStepsize(), rect,
  365. result->getPixelPointer(), result->getStepsize(),
  366. dstSize, xFactor, yFactor, interpolation);
  367. if(ret!=ippStsNoErr)
  368. fthrow(ImageException, ippGetStatusString(ret));
  369. return result;
  370. #else // NICE_USELIB_IPP
  371. fthrow(ImageException,"Not yet supported without IPP.");
  372. #endif // NICE_USELIB_IPP
  373. }
  374. template<class P>
  375. ColorImageT<P>* scale(const ColorImageT<P>& src, ColorImageT<P>* dst, double xFactor, double yFactor, int interpolation)
  376. {
  377. #ifdef NICE_USELIB_IPP
  378. IppiRect rect = makeRectFullImage(src);
  379. IppiSize dstSize;
  380. if(isZero(xFactor) && dst!=NULL) {
  381. dstSize.width = dst->width();
  382. xFactor=dst->width()/(double)src.width();
  383. } else
  384. dstSize.width = (int) ceil ((double) src.width () * xFactor);
  385. if(isZero(yFactor) && dst!=NULL) {
  386. dstSize.height = dst->height();
  387. yFactor=dst->height()/(double)src.height();
  388. } else
  389. dstSize.height = (int) ceil ((double)src.height () * yFactor);
  390. ColorImageT<P> * result = createResultBuffer(dstSize.width, dstSize.height, dst);
  391. IppStatus ret = ippiResize_C3R(src.getPixelPointer(), makeROIFullImage(src), src.getStepsize(), rect,
  392. result->getPixelPointer(), result->getStepsize(), dstSize,
  393. xFactor, yFactor, interpolation);
  394. if(ret!=ippStsNoErr)
  395. fthrow(ImageException, ippGetStatusString(ret));
  396. return result;
  397. #else // NICE_USELIB_IPP
  398. fthrow(ImageException,"Not yet supported without IPP.");
  399. #endif // NICE_USELIB_IPP
  400. }
  401. template<class P>
  402. ColorImageT<Ipp8u>* signedImageToRGB(const ImageT<P>& image,
  403. ColorImageT<Ipp8u>* colored) {
  404. //fthrow(ImageException, "signedImageToRGB() not supported for this pixel type");
  405. ColorImageT<Ipp8u> *result = createResultBuffer(image, colored);
  406. P vmin;
  407. P vmax;
  408. image.minmax(vmin, vmax);
  409. const P scale = std::max(vmax, static_cast<P>(-vmin));
  410. const Ipp8u black[3] = {0,0,0};
  411. *result = black;
  412. if (vmax == 0) {
  413. return result;
  414. }
  415. // FIXME not efficient
  416. for (int y = 0; y < image.height(); y++) {
  417. for (int x = 0; x < image.width(); x++) {
  418. const P pixel = image.getPixel(x, y);
  419. if (pixel < P(0)) {
  420. const Ipp8u newPixel = static_cast<Ipp8u>(-pixel * P(255) / scale);
  421. (*result)(x,y,0) = newPixel;
  422. } else {
  423. const Ipp8u newPixel = static_cast<Ipp8u>(pixel * P(255) / scale);
  424. (*result)(x,y,0) = newPixel;
  425. (*result)(x,y,1) = newPixel;
  426. (*result)(x,y,2) = newPixel;
  427. }
  428. }
  429. }
  430. return result;
  431. }
  432. } // namespace