perf_tsdf.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html
  4. #include "perf_precomp.hpp"
  5. namespace opencv_test { namespace {
  6. using namespace cv;
  7. /** Reprojects screen point to camera space given z coord. */
  8. struct Reprojector
  9. {
  10. Reprojector() {}
  11. inline Reprojector(Matx33f intr)
  12. {
  13. fxinv = 1.f / intr(0, 0), fyinv = 1.f / intr(1, 1);
  14. cx = intr(0, 2), cy = intr(1, 2);
  15. }
  16. template<typename T>
  17. inline cv::Point3_<T> operator()(cv::Point3_<T> p) const
  18. {
  19. T x = p.z * (p.x - cx) * fxinv;
  20. T y = p.z * (p.y - cy) * fyinv;
  21. return cv::Point3_<T>(x, y, p.z);
  22. }
  23. float fxinv, fyinv, cx, cy;
  24. };
  25. template<class Scene>
  26. struct RenderInvoker : ParallelLoopBody
  27. {
  28. RenderInvoker(Mat_<float>& _frame, Affine3f _pose,
  29. Reprojector _reproj, float _depthFactor, bool _onlySemisphere)
  30. : ParallelLoopBody(),
  31. frame(_frame),
  32. pose(_pose),
  33. reproj(_reproj),
  34. depthFactor(_depthFactor),
  35. onlySemisphere(_onlySemisphere)
  36. { }
  37. virtual void operator ()(const cv::Range& r) const
  38. {
  39. for (int y = r.start; y < r.end; y++)
  40. {
  41. float* frameRow = frame[y];
  42. for (int x = 0; x < frame.cols; x++)
  43. {
  44. float pix = 0;
  45. Point3f orig = pose.translation();
  46. // direction through pixel
  47. Point3f screenVec = reproj(Point3f((float)x, (float)y, 1.f));
  48. float xyt = 1.f / (screenVec.x * screenVec.x +
  49. screenVec.y * screenVec.y + 1.f);
  50. Point3f dir = normalize(Vec3f(pose.rotation() * screenVec));
  51. // screen space axis
  52. dir.y = -dir.y;
  53. const float maxDepth = 20.f;
  54. const float maxSteps = 256;
  55. float t = 0.f;
  56. for (int step = 0; step < maxSteps && t < maxDepth; step++)
  57. {
  58. Point3f p = orig + dir * t;
  59. float d = Scene::map(p, onlySemisphere);
  60. if (d < 0.000001f)
  61. {
  62. float depth = std::sqrt(t * t * xyt);
  63. pix = depth * depthFactor;
  64. break;
  65. }
  66. t += d;
  67. }
  68. frameRow[x] = pix;
  69. }
  70. }
  71. }
  72. Mat_<float>& frame;
  73. Affine3f pose;
  74. Reprojector reproj;
  75. float depthFactor;
  76. bool onlySemisphere;
  77. };
  78. struct Scene
  79. {
  80. virtual ~Scene() {}
  81. static Ptr<Scene> create(Size sz, Matx33f _intr, float _depthFactor, bool onlySemisphere);
  82. virtual Mat depth(Affine3f pose) = 0;
  83. virtual std::vector<Affine3f> getPoses() = 0;
  84. };
  85. struct SemisphereScene : Scene
  86. {
  87. const int framesPerCycle = 72;
  88. const float nCycles = 0.25f;
  89. const Affine3f startPose = Affine3f(Vec3f(0.f, 0.f, 0.f), Vec3f(1.5f, 0.3f, -2.1f));
  90. Size frameSize;
  91. Matx33f intr;
  92. float depthFactor;
  93. bool onlySemisphere;
  94. SemisphereScene(Size sz, Matx33f _intr, float _depthFactor, bool _onlySemisphere) :
  95. frameSize(sz), intr(_intr), depthFactor(_depthFactor), onlySemisphere(_onlySemisphere)
  96. { }
  97. static float map(Point3f p, bool onlySemisphere)
  98. {
  99. float plane = p.y + 0.5f;
  100. Point3f spherePose = p - Point3f(-0.0f, 0.3f, 1.1f);
  101. float sphereRadius = 0.5f;
  102. float sphere = (float)cv::norm(spherePose) - sphereRadius;
  103. float sphereMinusBox = sphere;
  104. float subSphereRadius = 0.05f;
  105. Point3f subSpherePose = p - Point3f(0.3f, -0.1f, -0.3f);
  106. float subSphere = (float)cv::norm(subSpherePose) - subSphereRadius;
  107. float res;
  108. if (!onlySemisphere)
  109. res = min({ sphereMinusBox, subSphere, plane });
  110. else
  111. res = sphereMinusBox;
  112. return res;
  113. }
  114. Mat depth(Affine3f pose) override
  115. {
  116. Mat_<float> frame(frameSize);
  117. Reprojector reproj(intr);
  118. Range range(0, frame.rows);
  119. parallel_for_(range, RenderInvoker<SemisphereScene>(frame, pose, reproj, depthFactor, onlySemisphere));
  120. return std::move(frame);
  121. }
  122. std::vector<Affine3f> getPoses() override
  123. {
  124. std::vector<Affine3f> poses;
  125. for (int i = 0; i < framesPerCycle * nCycles; i++)
  126. {
  127. float angle = (float)(CV_2PI * i / framesPerCycle);
  128. Affine3f pose;
  129. pose = pose.rotate(startPose.rotation());
  130. pose = pose.rotate(Vec3f(0.f, -0.5f, 0.f) * angle);
  131. pose = pose.translate(Vec3f(startPose.translation()[0] * sin(angle),
  132. startPose.translation()[1],
  133. startPose.translation()[2] * cos(angle)));
  134. poses.push_back(pose);
  135. }
  136. return poses;
  137. }
  138. };
  139. Ptr<Scene> Scene::create(Size sz, Matx33f _intr, float _depthFactor, bool _onlySemisphere)
  140. {
  141. return makePtr<SemisphereScene>(sz, _intr, _depthFactor, _onlySemisphere);
  142. }
  143. // this is a temporary solution
  144. // ----------------------------
  145. typedef cv::Vec4f ptype;
  146. typedef cv::Mat_< ptype > Points;
  147. typedef Points Normals;
  148. typedef Size2i Size;
  149. template<int p>
  150. inline float specPow(float x)
  151. {
  152. if (p % 2 == 0)
  153. {
  154. float v = specPow<p / 2>(x);
  155. return v * v;
  156. }
  157. else
  158. {
  159. float v = specPow<(p - 1) / 2>(x);
  160. return v * v * x;
  161. }
  162. }
  163. template<>
  164. inline float specPow<0>(float /*x*/)
  165. {
  166. return 1.f;
  167. }
  168. template<>
  169. inline float specPow<1>(float x)
  170. {
  171. return x;
  172. }
  173. inline cv::Vec3f fromPtype(const ptype& x)
  174. {
  175. return cv::Vec3f(x[0], x[1], x[2]);
  176. }
  177. inline Point3f normalize(const Vec3f& v)
  178. {
  179. double nv = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  180. return v * (nv ? 1. / nv : 0.);
  181. }
  182. void renderPointsNormals(InputArray _points, InputArray _normals, OutputArray image, Affine3f lightPose)
  183. {
  184. Size sz = _points.size();
  185. image.create(sz, CV_8UC4);
  186. Points points = _points.getMat();
  187. Normals normals = _normals.getMat();
  188. Mat_<Vec4b> img = image.getMat();
  189. Range range(0, sz.height);
  190. const int nstripes = -1;
  191. parallel_for_(range, [&](const Range&)
  192. {
  193. for (int y = range.start; y < range.end; y++)
  194. {
  195. Vec4b* imgRow = img[y];
  196. const ptype* ptsRow = points[y];
  197. const ptype* nrmRow = normals[y];
  198. for (int x = 0; x < sz.width; x++)
  199. {
  200. Point3f p = fromPtype(ptsRow[x]);
  201. Point3f n = fromPtype(nrmRow[x]);
  202. Vec4b color;
  203. if (cvIsNaN(p.x) || cvIsNaN(p.y) || cvIsNaN(p.z) )
  204. {
  205. color = Vec4b(0, 32, 0, 0);
  206. }
  207. else
  208. {
  209. const float Ka = 0.3f; //ambient coeff
  210. const float Kd = 0.5f; //diffuse coeff
  211. const float Ks = 0.2f; //specular coeff
  212. const int sp = 20; //specular power
  213. const float Ax = 1.f; //ambient color, can be RGB
  214. const float Dx = 1.f; //diffuse color, can be RGB
  215. const float Sx = 1.f; //specular color, can be RGB
  216. const float Lx = 1.f; //light color
  217. Point3f l = normalize(lightPose.translation() - Vec3f(p));
  218. Point3f v = normalize(-Vec3f(p));
  219. Point3f r = normalize(Vec3f(2.f * n * n.dot(l) - l));
  220. uchar ix = (uchar)((Ax * Ka * Dx + Lx * Kd * Dx * max(0.f, n.dot(l)) +
  221. Lx * Ks * Sx * specPow<sp>(max(0.f, r.dot(v)))) * 255.f);
  222. color = Vec4b(ix, ix, ix, 0);
  223. }
  224. imgRow[x] = color;
  225. }
  226. }
  227. }, nstripes);
  228. }
  229. // ----------------------------
  230. class Settings
  231. {
  232. public:
  233. Ptr<kinfu::Params> _params;
  234. Ptr<kinfu::Volume> volume;
  235. Ptr<Scene> scene;
  236. std::vector<Affine3f> poses;
  237. Settings(bool useHashTSDF)
  238. {
  239. if (useHashTSDF)
  240. _params = kinfu::Params::hashTSDFParams(true);
  241. else
  242. _params = kinfu::Params::coarseParams();
  243. volume = kinfu::makeVolume(_params->volumeType, _params->voxelSize, _params->volumePose.matrix,
  244. _params->raycast_step_factor, _params->tsdf_trunc_dist, _params->tsdf_max_weight,
  245. _params->truncateThreshold, _params->volumeDims);
  246. scene = Scene::create(_params->frameSize, _params->intr, _params->depthFactor, true);
  247. poses = scene->getPoses();
  248. }
  249. };
  250. void displayImage(Mat depth, UMat _points, UMat _normals, float depthFactor, Vec3f lightPose)
  251. {
  252. Mat points, normals, image;
  253. AccessFlag af = ACCESS_READ;
  254. normals = _normals.getMat(af);
  255. points = _points.getMat(af);
  256. patchNaNs(points);
  257. imshow("depth", depth * (1.f / depthFactor / 4.f));
  258. renderPointsNormals(points, normals, image, lightPose);
  259. imshow("render", image);
  260. waitKey(2000);
  261. }
  262. static const bool display = false;
  263. PERF_TEST(Perf_TSDF, integrate)
  264. {
  265. Settings settings(false);
  266. for (size_t i = 0; i < settings.poses.size(); i++)
  267. {
  268. Matx44f pose = settings.poses[i].matrix;
  269. Mat depth = settings.scene->depth(pose);
  270. startTimer();
  271. settings.volume->integrate(depth, settings._params->depthFactor, pose, settings._params->intr);
  272. stopTimer();
  273. depth.release();
  274. }
  275. SANITY_CHECK_NOTHING();
  276. }
  277. PERF_TEST(Perf_TSDF, raycast)
  278. {
  279. Settings settings(false);
  280. for (size_t i = 0; i < settings.poses.size(); i++)
  281. {
  282. UMat _points, _normals;
  283. Matx44f pose = settings.poses[i].matrix;
  284. Mat depth = settings.scene->depth(pose);
  285. settings.volume->integrate(depth, settings._params->depthFactor, pose, settings._params->intr);
  286. startTimer();
  287. settings.volume->raycast(pose, settings._params->intr, settings._params->frameSize, _points, _normals);
  288. stopTimer();
  289. if (display)
  290. displayImage(depth, _points, _normals, settings._params->depthFactor, settings._params->lightPose);
  291. }
  292. SANITY_CHECK_NOTHING();
  293. }
  294. PERF_TEST(Perf_HashTSDF, integrate)
  295. {
  296. Settings settings(true);
  297. for (size_t i = 0; i < settings.poses.size(); i++)
  298. {
  299. Matx44f pose = settings.poses[i].matrix;
  300. Mat depth = settings.scene->depth(pose);
  301. startTimer();
  302. settings.volume->integrate(depth, settings._params->depthFactor, pose, settings._params->intr);
  303. stopTimer();
  304. depth.release();
  305. }
  306. SANITY_CHECK_NOTHING();
  307. }
  308. PERF_TEST(Perf_HashTSDF, raycast)
  309. {
  310. Settings settings(true);
  311. for (size_t i = 0; i < settings.poses.size(); i++)
  312. {
  313. UMat _points, _normals;
  314. Matx44f pose = settings.poses[i].matrix;
  315. Mat depth = settings.scene->depth(pose);
  316. settings.volume->integrate(depth, settings._params->depthFactor, pose, settings._params->intr);
  317. startTimer();
  318. settings.volume->raycast(pose, settings._params->intr, settings._params->frameSize, _points, _normals);
  319. stopTimer();
  320. if (display)
  321. displayImage(depth, _points, _normals, settings._params->depthFactor, settings._params->lightPose);
  322. }
  323. SANITY_CHECK_NOTHING();
  324. }
  325. }} // namespace