PageRenderTime 29ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/vlVolume/VolumeUtils.cpp

http://github.com/VizLibrary/Visualization-Library
C++ | 337 lines | 270 code | 18 blank | 49 comment | 59 complexity | 92e2454404e01a8c03353b102036ee2e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0
  1. /**************************************************************************************/
  2. /* */
  3. /* Visualization Library */
  4. /* http://www.visualizationlibrary.org */
  5. /* */
  6. /* Copyright (c) 2005-2010, Michele Bosi */
  7. /* All rights reserved. */
  8. /* */
  9. /* Redistribution and use in source and binary forms, with or without modification, */
  10. /* are permitted provided that the following conditions are met: */
  11. /* */
  12. /* - Redistributions of source code must retain the above copyright notice, this */
  13. /* list of conditions and the following disclaimer. */
  14. /* */
  15. /* - Redistributions in binary form must reproduce the above copyright notice, this */
  16. /* list of conditions and the following disclaimer in the documentation and/or */
  17. /* other materials provided with the distribution. */
  18. /* */
  19. /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
  20. /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
  21. /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
  22. /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
  23. /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
  24. /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
  25. /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
  26. /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
  27. /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
  28. /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  29. /* */
  30. /**************************************************************************************/
  31. #include <vlVolume/VolumeUtils.hpp>
  32. #include <vlCore/Log.hpp>
  33. #include <vlCore/glsl_math.hpp>
  34. using namespace vl;
  35. //-----------------------------------------------------------------------------
  36. ref<Image> vl::genRGBAVolume(const Image* data, const Image* trfunc, const fvec3& light_dir, bool alpha_from_data)
  37. {
  38. ref<Image> img;
  39. if(data->type() == IT_UNSIGNED_BYTE)
  40. img = genRGBAVolumeT<unsigned char,IT_UNSIGNED_BYTE>(data,trfunc,light_dir,alpha_from_data);
  41. else
  42. if(data->type() == IT_UNSIGNED_SHORT)
  43. img = genRGBAVolumeT<unsigned short,IT_UNSIGNED_SHORT>(data,trfunc,light_dir,alpha_from_data);
  44. else
  45. if(data->type() == IT_FLOAT)
  46. img = genRGBAVolumeT<float,IT_FLOAT>(data,trfunc,light_dir,alpha_from_data);
  47. else
  48. Log::error("genRGBAVolume() called with non supported data type().\n");
  49. return img;
  50. }
  51. //-----------------------------------------------------------------------------
  52. ref<Image> vl::genRGBAVolume(const Image* data, const Image* trfunc, bool alpha_from_data)
  53. {
  54. ref<Image> img;
  55. if(data->type() == IT_UNSIGNED_BYTE)
  56. img = genRGBAVolumeT<unsigned char,IT_UNSIGNED_BYTE>(data,trfunc,alpha_from_data);
  57. else
  58. if(data->type() == IT_UNSIGNED_SHORT)
  59. img = genRGBAVolumeT<unsigned short,IT_UNSIGNED_SHORT>(data,trfunc,alpha_from_data);
  60. else
  61. if(data->type() == IT_FLOAT)
  62. img = genRGBAVolumeT<float,IT_FLOAT>(data,trfunc,alpha_from_data);
  63. else
  64. Log::error("genRGBAVolume() called with non supported data type().\n");
  65. return img;
  66. }
  67. //-----------------------------------------------------------------------------
  68. template<typename data_type, EImageType img_type>
  69. ref<Image> vl::genRGBAVolumeT(const Image* data, const Image* trfunc, const fvec3& light_dir, bool alpha_from_data)
  70. {
  71. if (!trfunc || !data)
  72. return NULL;
  73. if (data->format() != IF_LUMINANCE)
  74. {
  75. Log::error("genRGBAVolume() called with non IF_LUMINANCE data format().\n");
  76. return NULL;
  77. }
  78. if (data->type() != img_type)
  79. {
  80. Log::error("genRGBAVolume() called with invalid data type().\n");
  81. return NULL;
  82. }
  83. if (data->dimension() != ID_3D)
  84. {
  85. Log::error("genRGBAVolume() called with non 3D data.\n");
  86. return NULL;
  87. }
  88. if (trfunc->dimension() != ID_1D)
  89. {
  90. Log::error("genRGBAVolume() transfer function image must be an 1D image.\n");
  91. return NULL;
  92. }
  93. if (trfunc->format() != IF_RGBA)
  94. {
  95. Log::error("genRGBAVolume() transfer function format() must be IF_RGBA.\n");
  96. return NULL;
  97. }
  98. if (trfunc->type() != IT_UNSIGNED_BYTE)
  99. {
  100. Log::error("genRGBAVolume() transfer function format() must be IT_UNSIGNED_BYTE.\n");
  101. return NULL;
  102. }
  103. float normalizer_num = 0;
  104. switch(data->type())
  105. {
  106. case IT_UNSIGNED_BYTE: normalizer_num = 1.0f/255.0f; break;
  107. case IT_UNSIGNED_SHORT: normalizer_num = 1.0f/65535.0f; break;
  108. case IT_FLOAT: normalizer_num = 1.0f; break;
  109. default:
  110. break;
  111. }
  112. // light normalization
  113. fvec3 L = light_dir;
  114. L.normalize();
  115. int w = data->width();
  116. int h = data->height();
  117. int d = data->depth();
  118. int pitch = data->pitch();
  119. const unsigned char* lum_px = data->pixels();
  120. // generated volume
  121. ref<Image> volume = new Image( w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE );
  122. ubvec4* rgba_px = (ubvec4*)volume->pixels();
  123. for(int z=0; z<d; ++z)
  124. {
  125. int z1 = z-1;
  126. int z2 = z+1;
  127. z1 = clamp(z1, 0, d-1);
  128. z2 = clamp(z2, 0, d-1);
  129. for(int y=0; y<h; ++y)
  130. {
  131. int y1 = y-1;
  132. int y2 = y+1;
  133. y1 = clamp(y1, 0, h-1);
  134. y2 = clamp(y2, 0, h-1);
  135. for(int x=0; x<w; ++x, ++rgba_px)
  136. {
  137. // value
  138. float lum = (*(data_type*)(lum_px + x*sizeof(data_type) + y*pitch + z*pitch*h)) * normalizer_num;
  139. // value -> transfer function
  140. float xval = lum*trfunc->width();
  141. VL_CHECK(xval>=0)
  142. if (xval > trfunc->width()-1.001f)
  143. xval = trfunc->width()-1.001f;
  144. int ix1 = (int)xval;
  145. int ix2 = ix1+1;
  146. VL_CHECK(ix2<trfunc->width())
  147. float w21 = (float)fract(xval);
  148. float w11 = 1.0f - w21;
  149. fvec4 c11 = (fvec4)((ubvec4*)trfunc->pixels())[ix1];
  150. fvec4 c21 = (fvec4)((ubvec4*)trfunc->pixels())[ix2];
  151. fvec4 rgba = (c11*w11 + c21*w21)*(1.0f/255.0f);
  152. // bake the lighting
  153. int x1 = x-1;
  154. int x2 = x+1;
  155. x1 = clamp(x1, 0, w-1);
  156. x2 = clamp(x2, 0, w-1);
  157. data_type vx1 = (*(data_type*)(lum_px + x1*sizeof(data_type) + y *pitch + z *pitch*h));
  158. data_type vx2 = (*(data_type*)(lum_px + x2*sizeof(data_type) + y *pitch + z *pitch*h));
  159. data_type vy1 = (*(data_type*)(lum_px + x *sizeof(data_type) + y1*pitch + z *pitch*h));
  160. data_type vy2 = (*(data_type*)(lum_px + x *sizeof(data_type) + y2*pitch + z *pitch*h));
  161. data_type vz1 = (*(data_type*)(lum_px + x *sizeof(data_type) + y *pitch + z1*pitch*h));
  162. data_type vz2 = (*(data_type*)(lum_px + x *sizeof(data_type) + y *pitch + z2*pitch*h));
  163. fvec3 N1(float(vx1-vx2), float(vy1-vy2), float(vz1-vz2));
  164. N1.normalize();
  165. fvec3 N2 = -N1 * 0.15f;
  166. float l1 = max(dot(N1,L),0.0f);
  167. float l2 = max(dot(N2,L),0.0f); // opposite dim light to enhance 3D perception
  168. rgba.r() = rgba.r()*l1 + rgba.r()*l2+0.2f; // +0.2f = ambient light
  169. rgba.g() = rgba.g()*l1 + rgba.g()*l2+0.2f;
  170. rgba.b() = rgba.b()*l1 + rgba.b()*l2+0.2f;
  171. rgba.r() = clamp(rgba.r(), 0.0f, 1.0f);
  172. rgba.g() = clamp(rgba.g(), 0.0f, 1.0f);
  173. rgba.b() = clamp(rgba.b(), 0.0f, 1.0f);
  174. // map pixel
  175. rgba_px->r() = (unsigned char)(rgba.r()*255.0f);
  176. rgba_px->g() = (unsigned char)(rgba.g()*255.0f);
  177. rgba_px->b() = (unsigned char)(rgba.b()*255.0f);
  178. if (alpha_from_data)
  179. rgba_px->a() = (unsigned char)(lum*255.0f);
  180. else
  181. rgba_px->a() = (unsigned char)(rgba.a()*255.0f);
  182. }
  183. }
  184. }
  185. return volume;
  186. }
  187. //-----------------------------------------------------------------------------
  188. template<typename data_type, EImageType img_type>
  189. ref<Image> vl::genRGBAVolumeT(const Image* data, const Image* trfunc, bool alpha_from_data)
  190. {
  191. if (!trfunc || !data)
  192. return NULL;
  193. if (data->format() != IF_LUMINANCE)
  194. {
  195. Log::error("genRGBAVolume() called with non IF_LUMINANCE data format().\n");
  196. return NULL;
  197. }
  198. if (data->type() != img_type)
  199. {
  200. Log::error("genRGBAVolume() called with invalid data type().\n");
  201. return NULL;
  202. }
  203. if (data->dimension() != ID_3D)
  204. {
  205. Log::error("genRGBAVolume() called with non 3D data.\n");
  206. return NULL;
  207. }
  208. if (trfunc->dimension() != ID_1D)
  209. {
  210. Log::error("genRGBAVolume() transfer function image must be an 1D image.\n");
  211. return NULL;
  212. }
  213. if (trfunc->format() != IF_RGBA)
  214. {
  215. Log::error("genRGBAVolume() transfer function format() must be IF_RGBA.\n");
  216. return NULL;
  217. }
  218. if (trfunc->type() != IT_UNSIGNED_BYTE)
  219. {
  220. Log::error("genRGBAVolume() transfer function format() must be IT_UNSIGNED_BYTE.\n");
  221. return NULL;
  222. }
  223. float normalizer_num = 0;
  224. switch(data->type())
  225. {
  226. case IT_UNSIGNED_BYTE: normalizer_num = 1.0f/255.0f; break;
  227. case IT_UNSIGNED_SHORT: normalizer_num = 1.0f/65535.0f; break;
  228. case IT_FLOAT: normalizer_num = 1.0f; break;
  229. default:
  230. break;
  231. }
  232. // light normalization
  233. int w = data->width();
  234. int h = data->height();
  235. int d = data->depth();
  236. int pitch = data->pitch();
  237. const unsigned char* lum_px = data->pixels();
  238. // generated volume
  239. ref<Image> volume = new Image( w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE );
  240. ubvec4* rgba_px = (ubvec4*)volume->pixels();
  241. for(int z=0; z<d; ++z)
  242. {
  243. int z1 = z-1;
  244. int z2 = z+1;
  245. z1 = clamp(z1, 0, d-1);
  246. z2 = clamp(z2, 0, d-1);
  247. for(int y=0; y<h; ++y)
  248. {
  249. int y1 = y-1;
  250. int y2 = y+1;
  251. y1 = clamp(y1, 0, h-1);
  252. y2 = clamp(y2, 0, h-1);
  253. for(int x=0; x<w; ++x, ++rgba_px)
  254. {
  255. // value
  256. float lum = (*(data_type*)(lum_px + x*sizeof(data_type) + y*pitch + z*pitch*h)) * normalizer_num;
  257. // value -> transfer function
  258. float xval = lum*trfunc->width();
  259. VL_CHECK(xval>=0)
  260. if (xval > trfunc->width()-1.001f)
  261. xval = trfunc->width()-1.001f;
  262. int ix1 = (int)xval;
  263. int ix2 = ix1+1;
  264. VL_CHECK(ix2<trfunc->width())
  265. float w21 = (float)fract(xval);
  266. float w11 = 1.0f - w21;
  267. fvec4 c11 = (fvec4)((ubvec4*)trfunc->pixels())[ix1];
  268. fvec4 c21 = (fvec4)((ubvec4*)trfunc->pixels())[ix2];
  269. fvec4 rgba = (c11*w11 + c21*w21)*(1.0f/255.0f);
  270. // map pixel
  271. rgba_px->r() = (unsigned char)(rgba.r()*255.0f);
  272. rgba_px->g() = (unsigned char)(rgba.g()*255.0f);
  273. rgba_px->b() = (unsigned char)(rgba.b()*255.0f);
  274. if (alpha_from_data)
  275. rgba_px->a() = (unsigned char)(lum*255.0f);
  276. else
  277. rgba_px->a() = (unsigned char)(rgba.a()*255.0f);
  278. }
  279. }
  280. }
  281. return volume;
  282. }
  283. //-----------------------------------------------------------------------------
  284. ref<Image> vl::genGradientNormals(const Image* img)
  285. {
  286. ref<Image> gradient = new Image;
  287. gradient->allocate3D(img->width(), img->height(), img->depth(), 1, IF_RGB, IT_FLOAT);
  288. fvec3* px = (fvec3*)gradient->pixels();
  289. fvec3 A, B;
  290. for(int z=0; z<gradient->depth(); ++z)
  291. {
  292. for(int y=0; y<gradient->height(); ++y)
  293. {
  294. for(int x=0; x<gradient->width(); ++x)
  295. {
  296. // clamped coordinates
  297. int xp = x+1, xn = x-1;
  298. int yp = y+1, yn = y-1;
  299. int zp = z+1, zn = z-1;
  300. if (xn<0) xn = 0;
  301. if (yn<0) yn = 0;
  302. if (zn<0) zn = 0;
  303. if (xp>img->width() -1) xp = img->width() -1;
  304. if (yp>img->height()-1) yp = img->height()-1;
  305. if (zp>img->depth() -1) zp = img->depth() -1;
  306. A.x() = img->sample(xn,y,z).r();
  307. B.x() = img->sample(xp,y,z).r();
  308. A.y() = img->sample(x,yn,z).r();
  309. B.y() = img->sample(x,yp,z).r();
  310. A.z() = img->sample(x,y,zn).r();
  311. B.z() = img->sample(x,y,zp).r();
  312. // write normal packed into 0..1 format
  313. px[x + img->width()*y + img->width()*img->height()*z] = normalize(A - B) * 0.5f + 0.5f;
  314. }
  315. }
  316. }
  317. return gradient;
  318. }
  319. //-----------------------------------------------------------------------------