Convert.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. #include "core/image/Convert.h"
  2. using namespace std;
  3. namespace NICE {
  4. ColorImage* rgbToHSV(const ColorImage& src, ColorImage* dst)
  5. {
  6. ColorImage* result = createResultBuffer(src, dst);
  7. #ifdef NICE_USELIB_IPP
  8. IppStatus ret = ippiRGBToHSV_8u_C3R(src.getPixelPointer(), src.getStepsize(),
  9. result->getPixelPointer(), result->getStepsize(),
  10. makeROIFullImage(src));
  11. if(ret!=ippStsNoErr)
  12. fthrow(ImageException, ippGetStatusString(ret));
  13. #else // NICE_USELIB_IPP
  14. double min,max,diff, r,g,b, h;
  15. const Ipp8u* pSrcStart = src.getPixelPointer();
  16. Ipp8u* pDstStart = result->getPixelPointer();
  17. const Ipp8u* pSrc;
  18. Ipp8u* pDst;
  19. for(int y=0; y<src.height(); ++y) {
  20. pSrc = pSrcStart;
  21. pDst = pDstStart;
  22. for(int x=0; x<src.width(); ++x) {
  23. r = *pSrc/255.0; ++pSrc;
  24. g = *pSrc/255.0; ++pSrc;
  25. b = *pSrc/255.0; ++pSrc;
  26. min = std::min(g,b);
  27. min = std::min(r, min);
  28. max = std::max(g,b);
  29. max = std::max(r, max);
  30. diff = max-min;
  31. // H
  32. h = 0;
  33. if(diff!=0) {
  34. if(max==r) { h = ((g-b)/diff )*60; }
  35. else if(max==g) { h = ((b-r)/diff + 2)*60; }
  36. else if(max==b) { h = ((r-g)/diff + 4)*60; }
  37. }
  38. h += (h<0)?360:0;
  39. *pDst = static_cast<unsigned char>(h*17/24); ++pDst; // *255/360
  40. *pDst = static_cast<unsigned char>((max==0)?0:(diff*255)/max); ++pDst;
  41. *pDst = static_cast<unsigned char>(max*255); ++pDst; // v = max;
  42. }
  43. pSrcStart += src.getStepsize();
  44. pDstStart += result->getStepsize();
  45. }
  46. #endif // NICE_USELIB_IPP
  47. return result;
  48. }
  49. ColorImage* hsvToRGB(const ColorImage& src, ColorImage* dst)
  50. {
  51. ColorImage* result = createResultBuffer(src.width(), src.height(), dst);
  52. #ifdef NICE_USELIB_IPP
  53. IppStatus ret = ippiHSVToRGB_8u_C3R(src.getPixelPointer(), src.getStepsize(),
  54. result->getPixelPointer(), result->getStepsize(),
  55. makeROIFullImage(src));
  56. if(ret!=ippStsNoErr)
  57. fthrow(ImageException, ippGetStatusString(ret));
  58. #else // NICE_USELIB_IPP
  59. double h,s,v, r,g,b, k,m,n, f;
  60. int i;
  61. const Ipp8u* pSrcStart = src.getPixelPointer();
  62. Ipp8u* pDstStart = result->getPixelPointer();
  63. const ColorImage::Pixel* pSrc;
  64. ColorImage::Pixel* pDst;
  65. for(int y=0; y<src.height(); ++y) {
  66. pSrc = pSrcStart;
  67. pDst = pDstStart;
  68. for(int x=0; x<src.width(); ++x) {
  69. h =(*pSrc/255.0)*360; ++pSrc;
  70. s = *pSrc/255.0; ++pSrc;
  71. v = *pSrc/255.0; ++pSrc;
  72. r = g = b = v; // default case if s==0
  73. if(s!=0) {
  74. h = (h==360)?0:h/60;
  75. i = static_cast<int>(h);
  76. f = h-i;
  77. m = v*(1-s);
  78. n = v*(1-s*f);
  79. k = v*(1-s*(1-f));
  80. switch(i) {
  81. case 0: r = v; g = k; b = m; break;
  82. case 1: r = n; g = v; b = m; break;
  83. case 2: r = m; g = v; b = k; break;
  84. case 3: r = m; g = n; b = v; break;
  85. case 4: r = k; g = m; b = v; break;
  86. case 5: r = v; g = m; b = n; break;
  87. }
  88. }
  89. *pDst = static_cast<Ipp8u>(r*255); ++pDst;
  90. *pDst = static_cast<Ipp8u>(g*255); ++pDst;
  91. *pDst = static_cast<Ipp8u>(b*255); ++pDst;
  92. }
  93. pSrcStart += src.getStepsize();
  94. pDstStart += result->getStepsize();
  95. }
  96. #endif // NICE_USELIB_IPP
  97. return(result);
  98. }
  99. ColorImage* rgbToYUV(const ColorImage& src, ColorImage* dst)
  100. {
  101. ColorImage* result = createResultBuffer(src.width(), src.height(), dst);
  102. #ifdef NICE_USELIB_IPP
  103. IppStatus ret = ippiRGBToYUV_8u_C3R(src.getPixelPointer(), src.getStepsize(),
  104. result->getPixelPointer(), result->getStepsize(),
  105. makeROIFullImage(src));
  106. if(ret!=ippStsNoErr)
  107. fthrow(ImageException, ippGetStatusString(ret));
  108. #else // NICE_USELIB_IPP
  109. double r,g,b, y,u,v;
  110. const Ipp8u* pSrcStart = src.getPixelPointer();
  111. Ipp8u* pDstStart = result->getPixelPointer();
  112. const ColorImage::Pixel* pSrc;
  113. ColorImage::Pixel* pDst;
  114. for(int ty=0; ty<src.height(); ++ty) {
  115. pSrc = pSrcStart;
  116. pDst = pDstStart;
  117. for(int tx=0; tx<src.width(); ++tx) {
  118. r = *pSrc/255.0; ++pSrc;
  119. g = *pSrc/255.0; ++pSrc;
  120. b = *pSrc/255.0; ++pSrc;
  121. y = 0.299*r + 0.587*g + 0.114*b;
  122. u = 0.492*(b-y);
  123. v = 0.877*(r-y);
  124. v+= 0.5;
  125. v = std::max(0.0, v);
  126. v = std::min(1.0, v);
  127. *pDst = static_cast<Ipp8u>(y*255); ++pDst;
  128. *pDst = static_cast<Ipp8u>((u+0.5)*255); ++pDst;
  129. *pDst = static_cast<Ipp8u>(v*255); ++pDst;
  130. }
  131. pSrcStart += src.getStepsize();
  132. pDstStart += result->getStepsize();
  133. }
  134. #endif // NICE_USELIB_IPP
  135. return result;
  136. }
  137. ColorImage* yuvToRGB(const ColorImage& src, ColorImage* dst)
  138. {
  139. ColorImage* result = createResultBuffer(src.width(), src.height(), dst);
  140. #ifdef NICE_USELIB_IPP
  141. IppStatus ret = ippiYUVToRGB_8u_C3R(src.getPixelPointer(), src.getStepsize(),
  142. result->getPixelPointer(), result->getStepsize(),
  143. makeROIFullImage(src));
  144. if(ret!=ippStsNoErr)
  145. fthrow(ImageException, ippGetStatusString(ret));
  146. #else // NICE_USELIB_IPP
  147. double y,u,v, r,g,b;
  148. const Ipp8u* pSrcStart = src.getPixelPointer();
  149. Ipp8u* pDstStart = result->getPixelPointer();
  150. const ColorImage::Pixel* pSrc;
  151. ColorImage::Pixel* pDst;
  152. for(int ty=0; ty<src.height(); ++ty) {
  153. pSrc = pSrcStart;
  154. pDst = pDstStart;
  155. for(int tx=0; tx<src.width(); ++tx) {
  156. y = *pSrc/255.0; ++pSrc;
  157. u = *pSrc/255.0-0.5; ++pSrc;
  158. v = *pSrc/255.0-0.5; ++pSrc;
  159. r = y + 1.140*v;
  160. g = y - 0.394*u - 0.581*v;
  161. b = y + 2.032*u;
  162. r = std::min(1.0, r);
  163. r = std::max(0.0, r);
  164. g = std::min(1.0, g);
  165. g = std::max(0.0, g);
  166. b = std::min(1.0, b);
  167. b = std::max(0.0, b);
  168. *pDst = static_cast<Ipp8u>(r*255); ++pDst;
  169. *pDst = static_cast<Ipp8u>(g*255); ++pDst;
  170. *pDst = static_cast<Ipp8u>(b*255); ++pDst;
  171. }
  172. pSrcStart += src.getStepsize();
  173. pDstStart += result->getStepsize();
  174. }
  175. #endif // NICE_USELIB_IPP
  176. return result;
  177. }
  178. // create a LUT for rgbToGray conversion
  179. ImageT<int>* rgbToGrayLUT()
  180. {
  181. ImageT<int>* result = new ImageT<int>(256,3);
  182. for(int i=0; i<256; ++i) {
  183. result->setPixelQuick(i,0, static_cast<int>(0.299*i));
  184. result->setPixelQuick(i,1, static_cast<int>(0.587*i));
  185. result->setPixelQuick(i,2, static_cast<int>(0.114*i));
  186. }
  187. return result;
  188. }
  189. // float-rgb conversion
  190. FloatImage* rgbToFloat(const ColorImage& src, FloatImage* dst)
  191. {
  192. FloatImage* result = createResultBuffer(src.width()*3, src.height(), dst);
  193. #ifdef NICE_USELIB_IPP
  194. IppStatus ret = ippiConvert_8u32f_C3R(src.getPixelPointer(), src.getStepsize(),
  195. result->getPixelPointer(), result->getStepsize(),
  196. makeROIFullImage(src));
  197. if(ret!=ippStsNoErr)
  198. fthrow(ImageException, ippGetStatusString(ret));
  199. #else
  200. const ColorImage::Pixel* pSrc;
  201. FloatImage::Pixel* pDst;
  202. for(int y=0; y<src.height(); ++y) {
  203. pSrc = src.getPixelPointerY(y);
  204. pDst = result->getPixelPointerY(y);
  205. for(int x=0; x<3*src.width(); ++x,++pSrc,++pDst)
  206. *pDst = static_cast<Ipp32f>(*pSrc);
  207. }
  208. #endif
  209. return result;
  210. }
  211. Image* floatToGrayScaled(const FloatImage& src, Ipp32f fmin, Ipp32f fmax, Image* dst)
  212. {
  213. Image* result = createResultBuffer(src.width(), src.height(), dst);
  214. #ifdef NICE_USELIB_IPP
  215. IppStatus ret = ippiScale_C1R(src.getPixelPointer(), src.getStepsize(),
  216. result->getPixelPointer(), result->getStepsize(),
  217. makeROIFullImage(src), fmin, fmax);
  218. if(ret!=ippStsNoErr)
  219. fthrow(ImageException, ippGetStatusString(ret));
  220. #else // NICE_USELIB_IPP
  221. double k = 255/(fmax-fmin);
  222. const Ipp32f* pSrc;
  223. Ipp8u* pDst;
  224. for(int y=0; y<src.height(); ++y) {
  225. pSrc = src.getPixelPointerY(y);
  226. pDst = result->getPixelPointerY(y);
  227. for(int x=0; x<src.width(); ++x,++pSrc,++pDst)
  228. *pDst = static_cast<Ipp8u>(k*(*pSrc-fmin));
  229. }
  230. #endif // NICE_USELIB_IPP
  231. return result;
  232. }
  233. Image* floatToGrayScaled(const FloatImage& src, Image* dst)
  234. {
  235. Ipp32f fmin, fmax;
  236. src.minmax(fmin, fmax);
  237. // make sure fmin is not equal to fmax
  238. if (isEqual(fmin, fmax, 1e-6f)) {
  239. fmax = fmin + 1.0f;
  240. }
  241. return floatToGrayScaled(src, fmin, fmax, dst);
  242. }
  243. Image* remap(const Image& src, const FloatImage &px, const FloatImage &py, Image* dst, int interpolation)
  244. {
  245. #ifdef NICE_USELIB_IPP
  246. Image * result = createResultBuffer(src.width(), src.height(), dst);
  247. Image gi(src);
  248. *(gi.getPixelPointerY(0)) = 0;
  249. IppStatus ret = ippiRemap_8u_C1R(gi.getPixelPointer(), makeROIFullImage(src), gi.getStepsize(),
  250. makeRectFullImage(gi), px.getPixelPointer(), px.getStepsize(),
  251. py.getPixelPointer(), py.getStepsize(),
  252. result->getPixelPointer(), result->getStepsize(),
  253. makeROIFullImage(gi), interpolation);
  254. if(ret!=ippStsNoErr)
  255. fthrow(ImageException, ippGetStatusString(ret));
  256. return result;
  257. #else // NICE_USELIB_IPP
  258. fthrow(ImageException,"Not yet supported without IPP.");
  259. #endif // NICE_USELIB_IPP
  260. }
  261. ColorImage* remap(const ColorImage& src, const FloatImage &px, const FloatImage &py, ColorImage* dst, int interpolation)
  262. {
  263. #ifdef NICE_USELIB_IPP
  264. ColorImage ci(src);
  265. ColorImage::Pixel* cursor = ci.getPixelPointerY(0);
  266. *cursor++ = 0;
  267. *cursor++ = 0;
  268. *cursor = 0;
  269. ColorImage * result = createResultBuffer(ci.width(), ci.height(), dst);
  270. IppStatus ret = ippiRemap_8u_C3R(ci.getPixelPointer(), makeROIFullImage(ci), ci.getStepsize(),
  271. makeRectFullImage(ci),
  272. px.getPixelPointer(), px.getStepsize(),
  273. py.getPixelPointer(), py.getStepsize(),
  274. result->getPixelPointer(), result->getStepsize(),
  275. makeROIFullImage(ci), interpolation);
  276. if(ret!=ippStsNoErr)
  277. fthrow(ImageException, ippGetStatusString(ret));
  278. return result;
  279. #else // NICE_USELIB_IPP
  280. fthrow(ImageException,"Not yet supported without IPP.");
  281. #endif // NICE_USELIB_IPP
  282. }
  283. Rect clipRect(const MultiChannelImageAccess& image, const Rect& rect)
  284. {
  285. Rect result(rect);
  286. if (result.left < 0) {
  287. result.width += result.left;
  288. result.left = 0;
  289. }
  290. if (result.top < 0) {
  291. result.height += result.top;
  292. result.top = 0;
  293. }
  294. if (result.left >= image.width()) {
  295. result.left = image.width() - 1;
  296. result.width = 0;
  297. }
  298. if (result.top >= image.height()) {
  299. result.top = image.height() - 1;
  300. result.height = 0;
  301. }
  302. int maxWidth = image.width() - result.left;
  303. int maxHeight = image.height() - result.top;
  304. if (result.width >= maxWidth) {
  305. result.width = maxWidth;
  306. }
  307. if (result.height >= maxHeight) {
  308. result.height = maxHeight;
  309. }
  310. return result;
  311. }
  312. IppiRect makeRectFullImage(const MultiChannelImageAccess& image)
  313. {
  314. IppiRect ippiRect = {0, 0, image.width(), image.height()};
  315. return ippiRect;
  316. }
  317. IppiSize makeROIFullImage(const MultiChannelImageAccess& image)
  318. {
  319. IppiSize ippiSize = {image.width(), image.height()};
  320. return ippiSize;
  321. }
  322. IppiSize makeROIRect(const MultiChannelImageAccess& image, const Rect& rect)
  323. {
  324. Rect roi = clipRect(image, rect);
  325. IppiSize ippiSize = {roi.width, roi.height};
  326. return ippiSize;
  327. }
  328. void preventIppBug(IppiSize& ippiSize, Rect& clippedROI)
  329. {
  330. // there is a bug in IPP: if ippiSize.height == 1 the function won't return
  331. if(ippiSize.height==1)
  332. {
  333. ippiSize.height = 2;
  334. if (clippedROI.top > 0)
  335. clippedROI.top--;
  336. }
  337. // maybe there is the same problem when ippiSize.width == 1
  338. if(ippiSize.width==1)
  339. {
  340. ippiSize.width = 2;
  341. if (clippedROI.left > 0)
  342. clippedROI.left--;
  343. }
  344. }
  345. void convertToPseudoColor ( double x, double & r, double & g, double & b )
  346. {
  347. if ( x < 0 || x > 1 )
  348. {
  349. fthrow(Exception, "Unable to convert a value outside of [0,1] to a pseudo color.");
  350. }
  351. size_t seg = ( size_t ) ( x * 6.0 );
  352. double y = ( 6 * x - seg );
  353. switch ( seg ) {
  354. case 0:
  355. r = 0.0;
  356. g = 0.0;
  357. b = y;
  358. break;
  359. case 1:
  360. r = 0.0;
  361. g = y;
  362. b = 1.0;
  363. break;
  364. case 2:
  365. r = 0.0;
  366. g = 1.0;
  367. b = 1.0 - y;
  368. break;
  369. case 3:
  370. r = y;
  371. g = 1.0;
  372. b = 0.0;
  373. break;
  374. case 4:
  375. r = 1.0;
  376. g = 1.0 - y;
  377. b = 0.0;
  378. break;
  379. case 5:
  380. r = 1.0;
  381. g = y;
  382. b = y;
  383. break;
  384. default:
  385. r = 1.0;
  386. g = 1.0;
  387. b = 1.0;
  388. break;
  389. }
  390. }
  391. } // namespace