AnnKrepchenko

Untitled

Jul 18th, 2017
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JSON 98.77 KB | None | 0 0
  1. {"_chunkSize":0,"_flag":"initialState","initialState":{"url":"https://m.habrahabr.ru/post/333532/","html":"<head record-id=\"2\"><base record-id=\"0\" href=\"https://m.habrahabr.ru/post/333532/\" target=\"_blank\"><!--record-id-13-->\n    <meta record-id=\"14\" charset=\"utf-8\"/><!--record-id-15-->\n    <title record-id=\"16\">Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне / Хабрахабр</title><!--record-id-17-->\n    <meta record-id=\"18\" content=\"Dynamic\" name=\"document-state\"/><!--record-id-19-->\n    <meta record-id=\"20\" name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0\"/><!--record-id-21-->\n    <link record-id=\"22\" href=\"https://habrahabr.ru/post/333532/\" rel=\"canonical\"/><!--record-id-23-->\n      <meta record-id=\"24\" property=\"fb:app_id\" content=\"444736788986613\"/><!--record-id-25-->\n<meta record-id=\"26\" property=\"og:type\" content=\"article\"/><!--record-id-27-->\n<meta record-id=\"28\" property=\"og:url\" content=\"https://habrahabr.ru/post/333532/\"/><!--record-id-29-->\n<meta record-id=\"30\" property=\"og:title\" content=\"Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне\"/><!--record-id-31-->\n\n    <meta record-id=\"32\" property=\"og:image\" content=\"https://habrastorage.org/web/b83/a96/f64/b83a96f643824c8aa4fe61f21a9ae3e2.gif\"/><!--record-id-33-->\n    <link record-id=\"34\" rel=\"image_src\" href=\"https://habrastorage.org/web/b83/a96/f64/b83a96f643824c8aa4fe61f21a9ae3e2.gif\"/><!--record-id-35-->\n    <meta record-id=\"36\" property=\"og:image\" content=\"https://habrastorage.org/web/474/be5/c08/474be5c0846f47e28218bfa8462185ff.jpg\"/><!--record-id-37-->\n    <link record-id=\"38\" rel=\"image_src\" href=\"https://habrastorage.org/web/474/be5/c08/474be5c0846f47e28218bfa8462185ff.jpg\"/><!--record-id-39-->\n    <meta record-id=\"40\" property=\"og:image\" content=\"https://habrastorage.org/web/9e9/daa/a53/9e9daaa5327049d2ba1fb3ce8b9c3828.jpg\"/><!--record-id-41-->\n    <link record-id=\"42\" rel=\"image_src\" href=\"https://habrastorage.org/web/9e9/daa/a53/9e9daaa5327049d2ba1fb3ce8b9c3828.jpg\"/><!--record-id-43-->\n    <meta record-id=\"44\" property=\"og:image\" content=\"https://habrastorage.org/web/431/572/6d6/4315726d67f34a8d8f1ff1180bbc7e78.png\"/><!--record-id-45-->\n    <link record-id=\"46\" rel=\"image_src\" href=\"https://habrastorage.org/web/431/572/6d6/4315726d67f34a8d8f1ff1180bbc7e78.png\"/><!--record-id-47-->\n    <meta record-id=\"48\" property=\"og:image\" content=\"https://habrastorage.org/web/0eb/1dd/e9e/0eb1dde9e6514aa4b01f52479ea0d101.gif\"/><!--record-id-49-->\n    <link record-id=\"50\" rel=\"image_src\" href=\"https://habrastorage.org/web/0eb/1dd/e9e/0eb1dde9e6514aa4b01f52479ea0d101.gif\"/><!--record-id-51-->\n    <meta record-id=\"52\" property=\"og:image\" content=\"https://habrastorage.org/web/8ba/e0d/937/8bae0d93754645d99869553c36214eaa.png\"/><!--record-id-53-->\n    <link record-id=\"54\" rel=\"image_src\" href=\"https://habrastorage.org/web/8ba/e0d/937/8bae0d93754645d99869553c36214eaa.png\"/><!--record-id-55-->\n    <meta record-id=\"56\" property=\"og:image\" content=\"https://habrastorage.org/web/e06/b99/04b/e06b9904b00b4ac6967fc6626ae40d52.jpg\"/><!--record-id-57-->\n    <link record-id=\"58\" rel=\"image_src\" href=\"https://habrastorage.org/web/e06/b99/04b/e06b9904b00b4ac6967fc6626ae40d52.jpg\"/><!--record-id-59-->\n    <meta record-id=\"60\" property=\"og:image\" content=\"https://habrastorage.org/web/f0b/c0d/e72/f0bc0de72b724920b6ae8e4d1fea3836.jpg\"/><!--record-id-61-->\n    <link record-id=\"62\" rel=\"image_src\" href=\"https://habrastorage.org/web/f0b/c0d/e72/f0bc0de72b724920b6ae8e4d1fea3836.jpg\"/><!--record-id-63-->\n    <meta record-id=\"64\" property=\"og:image\" content=\"https://habrastorage.org/web/ce4/7cd/e5b/ce47cde5b7ea45c69d62416da0d4d19c.png\"/><!--record-id-65-->\n    <link reco
  2. astorage.org/web/ce4/7cd/e5b/ce47cde5b7ea45c69d62416da0d4d19c.png\"/><!--record-id-67-->\n    <meta record-id=\"68\" property=\"og:image\" content=\"https://habrastorage.org/getpro/habr/formulas/8e3/e4b/3af/8e3e4b3af7c1321e593b77fb58c61afa.svg\"/><!--record-id-69-->\n    <link record-id=\"70\" rel=\"image_src\" href=\"https://habrastorage.org/getpro/habr/formulas/8e3/e4b/3af/8e3e4b3af7c1321e593b77fb58c61afa.svg\"/><!--record-id-71-->\n    <meta record-id=\"72\" property=\"og:image\" content=\"https://habrastorage.org/getpro/habr/formulas/e85/9e3/389/e859e33895fd579701b4da0969f53c18.svg\"/><!--record-id-73-->\n    <link record-id=\"74\" rel=\"image_src\" href=\"https://habrastorage.org/getpro/habr/formulas/e85/9e3/389/e859e33895fd579701b4da0969f53c18.svg\"/><!--record-id-75-->\n    <meta record-id=\"76\" property=\"og:image\" content=\"https://habrastorage.org/web/fd3/4c1/8a8/fd34c18a8e874103a40c365ddaec4fb7.gif\"/><!--record-id-77-->\n    <link record-id=\"78\" rel=\"image_src\" href=\"https://habrastorage.org/web/fd3/4c1/8a8/fd34c18a8e874103a40c365ddaec4fb7.gif\"/><!--record-id-79-->\n    <meta record-id=\"80\" property=\"og:image\" content=\"https://habrastorage.org/web/1a6/1b8/63c/1a61b863c8b3443a8b90b7531af1ccf3.gif\"/><!--record-id-81-->\n    <link record-id=\"82\" rel=\"image_src\" href=\"https://habrastorage.org/web/1a6/1b8/63c/1a61b863c8b3443a8b90b7531af1ccf3.gif\"/><!--record-id-83-->\n    <meta record-id=\"84\" property=\"og:image\" content=\"https://habrastorage.org/web/d18/cac/1fd/d18cac1fda3c47a48e43dfbde71fd77b.gif\"/><!--record-id-85-->\n    <link record-id=\"86\" rel=\"image_src\" href=\"https://habrastorage.org/web/d18/cac/1fd/d18cac1fda3c47a48e43dfbde71fd77b.gif\"/><!--record-id-87-->\n    <meta record-id=\"88\" property=\"og:image\" content=\"https://habrastorage.org/web/9f5/ec4/e19/9f5ec4e19ac842928c7c512c0a8864c0.gif\"/><!--record-id-89-->\n    <link record-id=\"90\" rel=\"image_src\" href=\"https://habrastorage.org/web/9f5/ec4/e19/9f5ec4e19ac842928c7c512c0a8864c0.gif\"/><!--record-id-91-->\n    <meta record-id=\"92\" property=\"og:image\" content=\"https://habrastorage.org/web/8ae/9f7/71d/8ae9f771d94746b99bbe327b8adcb7d4.gif\"/><!--record-id-93-->\n    <link record-id=\"94\" rel=\"image_src\" href=\"https://habrastorage.org/web/8ae/9f7/71d/8ae9f771d94746b99bbe327b8adcb7d4.gif\"/><!--record-id-95-->\n    <meta record-id=\"96\" property=\"og:image\" content=\"https://habrastorage.org/web/379/d5e/1a7/379d5e1a72174becb64f991f0b3455fc.gif\"/><!--record-id-97-->\n    <link record-id=\"98\" rel=\"image_src\" href=\"https://habrastorage.org/web/379/d5e/1a7/379d5e1a72174becb64f991f0b3455fc.gif\"/><!--record-id-99-->\n    <meta record-id=\"100\" property=\"og:image\" content=\"https://habrastorage.org/web/d68/1b4/00b/d681b400b40f49abb86f51e474df8589.gif\"/><!--record-id-101-->\n    <link record-id=\"102\" rel=\"image_src\" href=\"https://habrastorage.org/web/d68/1b4/00b/d681b400b40f49abb86f51e474df8589.gif\"/><!--record-id-103-->\n    <meta record-id=\"104\" property=\"og:image\" content=\"https://habrastorage.org/web/7b2/e18/fc4/7b2e18fc49164a6689e6b8cc3729e6b6.gif\"/><!--record-id-105-->\n    <link record-id=\"106\" rel=\"image_src\" href=\"https://habrastorage.org/web/7b2/e18/fc4/7b2e18fc49164a6689e6b8cc3729e6b6.gif\"/><!--record-id-107-->\n    <meta record-id=\"108\" property=\"og:image\" content=\"https://habrastorage.org/web/232/c88/5ec/232c885ec6384eb7a3e8422e4139ab7e.gif\"/><!--record-id-109-->\n    <link record-id=\"110\" rel=\"image_src\" href=\"https://habrastorage.org/web/232/c88/5ec/232c885ec6384eb7a3e8422e4139ab7e.gif\"/><!--record-id-111-->\n    <meta record-id=\"112\" property=\"og:image\" content=\"https://habrastorage.org/web/ad8/0b5/218/ad80b521856f48fa9a87b46fc6a15a71.gif\"/><!--record-id-113-->\n    <link record-id=\"114\" rel=\"image_src\" href=\"https://habrastorage.org/web/ad8/0b5/218/ad80b521856f48fa9a87b46fc6a15a71.gif\"/><!--record-id-115-->\n    <meta record-id=\"116\" property=\"og:imag
  3. e\" content=\"https://habrastorage.org/web/b4b/621/55a/b4b62155a8834025859113e5181236af.gif\"/><!--record-id-117-->\n    <link record-id=\"118\" rel=\"image_src\" href=\"https://habrastorage.org/web/b4b/621/55a/b4b62155a8834025859113e5181236af.gif\"/><!--record-id-119-->\n    <meta record-id=\"120\" property=\"og:image\" content=\"https://habrastorage.org/getpro/habr/formulas/ce4/434/132/ce443413279406b7072efe33460de6fd.svg\"/><!--record-id-121-->\n    <link record-id=\"122\" rel=\"image_src\" href=\"https://habrastorage.org/getpro/habr/formulas/ce4/434/132/ce443413279406b7072efe33460de6fd.svg\"/><!--record-id-123-->\n    <meta record-id=\"124\" property=\"og:image\" content=\"https://habrastorage.org/getpro/habr/formulas/08d/9fa/efb/08d9faefbe272bdf8fbb80773542e343.svg\"/><!--record-id-125-->\n    <link record-id=\"126\" rel=\"image_src\" href=\"https://habrastorage.org/getpro/habr/formulas/08d/9fa/efb/08d9faefbe272bdf8fbb80773542e343.svg\"/><!--record-id-127-->\n    <meta record-id=\"128\" property=\"og:image\" content=\"https://habrastorage.org/web/613/64a/b08/61364ab087054dae8c826c233a53ac16.gif\"/><!--record-id-129-->\n    <link record-id=\"130\" rel=\"image_src\" href=\"https://habrastorage.org/web/613/64a/b08/61364ab087054dae8c826c233a53ac16.gif\"/><!--record-id-131-->\n    <meta record-id=\"132\" property=\"og:image\" content=\"https://habrastorage.org/web/e52/91c/72f/e5291c72fb3c477da9f268b9a63452f3.gif\"/><!--record-id-133-->\n    <link record-id=\"134\" rel=\"image_src\" href=\"https://habrastorage.org/web/e52/91c/72f/e5291c72fb3c477da9f268b9a63452f3.gif\"/><!--record-id-135-->\n    <meta record-id=\"136\" property=\"og:image\" content=\"https://habrastorage.org/web/817/3e1/fe3/8173e1fe350243c8b80f9003b26e4818.gif\"/><!--record-id-137-->\n    <link record-id=\"138\" rel=\"image_src\" href=\"https://habrastorage.org/web/817/3e1/fe3/8173e1fe350243c8b80f9003b26e4818.gif\"/><!--record-id-139-->\n    <meta record-id=\"140\" property=\"og:image\" content=\"https://habrastorage.org/web/934/43a/711/93443a7116b84070a14eaa70a5007311.gif\"/><!--record-id-141-->\n    <link record-id=\"142\" rel=\"image_src\" href=\"https://habrastorage.org/web/934/43a/711/93443a7116b84070a14eaa70a5007311.gif\"/><!--record-id-143-->\n    <meta record-id=\"144\" property=\"og:image\" content=\"https://habrastorage.org/web/915/9e6/a7f/9159e6a7f5044cdcb3718c411583f0ed.gif\"/><!--record-id-145-->\n    <link record-id=\"146\" rel=\"image_src\" href=\"https://habrastorage.org/web/915/9e6/a7f/9159e6a7f5044cdcb3718c411583f0ed.gif\"/><!--record-id-147-->\n    <meta record-id=\"148\" property=\"og:image\" content=\"https://habrastorage.org/web/d76/914/cd0/d76914cd0c024cc98cb01a1166388ac5.gif\"/><!--record-id-149-->\n    <link record-id=\"150\" rel=\"image_src\" href=\"https://habrastorage.org/web/d76/914/cd0/d76914cd0c024cc98cb01a1166388ac5.gif\"/><!--record-id-151-->\n\n<meta record-id=\"152\" property=\"og:description\" content=\"Привет Хабр! Это заметка о небольшом хобби-проекте, которым я занимался в свободное время. Я расскажу, как с помощью несложных алгоритмов превращать карты...\"/><!--record-id-153-->\n<meta record-id=\"154\" name=\"twitter:card\" content=\"summary\"/><!--record-id-155-->\n<meta record-id=\"156\" name=\"twitter:site\" content=\"@habrahabr\"/><!--record-id-157-->\n  <meta record-id=\"158\" property=\"al:android:url\" content=\"habrahabr://post/333532\"/><!--record-id-159-->\n<meta record-id=\"160\" property=\"al:android:app_name\" content=\"Habrahabr\"/><!--record-id-161-->\n<meta record-id=\"162\" property=\"al:android:package\" content=\"ru.habrahabr\"/><!--record-id-163-->\n<meta record-id=\"164\" property=\"al:windows_phone:url\" content=\"habrahabr://post/333532\"/><!--record-id-165-->\n<meta record-id=\"166\" property=\"al:windows_phone:app_name\" content=\"Habrahabr\"/><!--record-id-167-->\n<meta record-id=\"168\" property=\"al:windows_phone:app_id\" conte
  4. <meta record-id=\"170\" name=\"google-play-app\" content=\"app-id=ru.habrahabr\"/><!--record-id-171-->\n    <meta record-id=\"172\" content=\"Хабрахабр\" name=\"apple-mobile-web-app-title\"/><!--record-id-173-->\n\n<link record-id=\"174\" rel=\"apple-touch-icon-precomposed\" sizes=\"57x57\" href=\"/images/favicons/apple-touch-icon-57x57.png\"/><!--record-id-175-->\n<link record-id=\"176\" rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"/images/favicons/apple-touch-icon-114x114.png\"/><!--record-id-177-->\n<link record-id=\"178\" rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"/images/favicons/apple-touch-icon-72x72.png\"/><!--record-id-179-->\n<link record-id=\"180\" rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"/images/favicons/apple-touch-icon-144x144.png\"/><!--record-id-181-->\n<link record-id=\"182\" rel=\"apple-touch-icon-precomposed\" sizes=\"120x120\" href=\"/images/favicons/apple-touch-icon-120x120.png\"/><!--record-id-183-->\n<link record-id=\"184\" rel=\"apple-touch-icon-precomposed\" sizes=\"152x152\" href=\"/images/favicons/apple-touch-icon-152x152.png\"/><!--record-id-185-->\n<link record-id=\"186\" rel=\"icon\" type=\"image/png\" href=\"/images/favicons/favicon-32x32.png\" sizes=\"32x32\"/><!--record-id-187-->\n<link record-id=\"188\" rel=\"icon\" type=\"image/png\" href=\"/images/favicons/favicon-16x16.png\" sizes=\"16x16\"/><!--record-id-189-->\n<meta record-id=\"190\" name=\"application-name\" content=\"Хабрахабр\"/><!--record-id-191-->\n<meta record-id=\"192\" name=\"msapplication-TileColor\" content=\"#FFFFFF\"/><!--record-id-193-->\n<meta record-id=\"194\" name=\"msapplication-TileImage\" content=\"mstile-144x144.png\"/><!--record-id-195-->\n    <link record-id=\"196\" href=\"https://habracdn.net/habr/styles/1500301734/stylesheets.mobile.css\" rel=\"stylesheet\" media=\"all\"/><!--record-id-197-->\n    <!--record-id-199-->\n    <!--record-id-201-->\n<!--record-id-203-->\n  </head><!--record-id-206-->\n\n  <body record-id=\"207\"><!--record-id-208-->\n    <div record-id=\"209\" id=\"layout\"><!--record-id-210-->\n      <div record-id=\"211\" id=\"header\"><!--record-id-212-->\n  <a record-id=\"213\" href=\"/\" class=\"logo\"></a><!--record-id-214-->\n    <div record-id=\"215\" class=\"title\"><!--record-id-216-->Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне / Хабрахабр</div><!--record-id-217-->\n  <div record-id=\"218\" class=\"toggle_sidebar\"></div><!--record-id-219-->\n</div><!--record-id-220-->\n      <div record-id=\"221\" id=\"content\"><!--record-id-222-->\n            <div record-id=\"223\" class=\"banner_header\"><!--record-id-224-->\n  <!--record-id-225--><!--  AdRiver code START. Type:AjaxJS Site: m.habr BN:1 --><!--record-id-226-->\n  <div record-id=\"227\" id=\"adriver_banner_1939188702\" style=\"margin: 0 auto;\" title=\"\"></div><!--record-id-228-->\n  <!--record-id-230-->\n  <!--record-id-231--><!--  AdRiver code END  --><!--record-id-232-->\n</div><!--record-id-233-->\n\n  <div record-id=\"234\" class=\"post_show\"><!--record-id-235-->\n      <div record-id=\"236\" class=\"hubs\"><!--record-id-237-->\n        <a record-id=\"238\" href=\"/hub/programming/\" class=\"hub\"><!--record-id-239-->Программирование</a><span record-id=\"240\" class=\"profiled_hub\" title=\"Профильный хаб\"><!--record-id-241-->*</span><!--record-id-242-->, \n        <a record-id=\"243\" href=\"/hub/algorithms/\" class=\"hub\"><!--record-id-244-->Алгоритмы</a><span record-id=\"245\" class=\"profiled_hub\" title=\"Профильный хаб\"><!--record-id-246-->*</span><!--record-id-247-->, \n        <a record-id=\"248\" href=\"/hub/cpp/\" class=\"hub\"><!--record-id-249-->C++</a><span record-id=\"250\" class=\"profiled_hub\" title=\"Профильный хаб\"><!--record-id-251-->*</span><!--record-id-252-->\n      </div><!--record-id-253-->\n\n    <h3 record-id=\"254\" class=\"title\"><!--record
  5. /\" class=\"flow\"><!--record-id-257-->Разработка</a><span record-id=\"258\" class=\"arrow\"><!--record-id-259--> → </span><!--record-id-260-->Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне\n    </h3><!--record-id-261-->\n\n    \n    \n    \n    <div record-id=\"262\" class=\"flag sandbox\"><!--record-id-263-->из песочницы</div><!--record-id-264--> \n\n    <div record-id=\"265\" class=\"meta\"><!--record-id-266-->\n      <a record-id=\"267\" href=\"/users/Petrenuk/topics/\" class=\"author\"><!--record-id-268-->Petrenuk</a><!--record-id-269-->\n      <span record-id=\"270\" class=\"time\"><!--record-id-271-->вчера в 17:42</span><!--record-id-272-->\n      <span record-id=\"273\" class=\"viewed icon_view\" title=\"Количество просмотров\"><!--record-id-274-->8,1k</span><!--record-id-275-->\n    </div><!--record-id-276-->\n\n    <div record-id=\"277\" class=\"text text_html js-mediator-article\" id=\"post_text\"><div record-id=\"278\" style=\"text-align:center;\"><img record-id=\"279\" src=\"https://habrastorage.org/web/b83/a96/f64/b83a96f643824c8aa4fe61f21a9ae3e2.gif\"/></div><br record-id=\"280\"/><!--record-id-281-->\nПривет Хабр! Это заметка о небольшом хобби-проекте, которым я занимался в свободное время. Я расскажу, как с помощью несложных алгоритмов превращать карты глубины от depth-сенсоров в забавный вид контента — динамические 3D сцены (их ещё называют 4D video, volumetric capture или free-viewpoint video). Моя любимая часть в этой работе — алгоритм триангуляции Делоне, который позволяет превращать разреженные облака точек в плотную полигональную сетку. Приглашаю всех, кому интересно почитать про алгоритмы, самописные велосипеды на C++11, и, конечно же, посмотреть на трёхмерных котиков.<br record-id=\"282\"/><!--record-id-283-->\n<br record-id=\"284\"/><!--record-id-285-->\nДля затравки: вот что получается при использовании RealSense R200: <a record-id=\"286\" href=\"https://skfb.ly/6snzt\"><!--record-id-287-->skfb.ly/6snzt</a><!--record-id-288--> (подождите несколько секунд для загрузки текстур, а затем используйте мышку, чтобы поворачивать сцену). Под катом есть ещё!<br record-id=\"289\"/><!--record-id-290-->\nОбладатели лимитированных тарифов, будьте осторожны. В статье много разных изображений и иллюстраций.<br record-id=\"291\"/><!--record-id-292-->\n<a record-id=\"293\" name=\"habracut\"></a><br record-id=\"294\"/><!--record-id-295-->\n<i record-id=\"296\"><!--record-id-297-->Дисклеймер: в этой статье не будет ни слова про искусственный интеллект, блокчейн или гравитационные волны. Это просто небольшая игрушка, которую я написал в основном для того, чтобы освежить C++ и OpenGL. Всё, ожидания сформированы, поехали!</i><br record-id=\"298\"/><!--record-id-299-->\n<br record-id=\"300\"/><!--record-id-301-->\nКакое-то время назад мне в руки попал девайс с 3D сенсором, а именно планшет <a record-id=\"302\" href=\"http://cdn.gsmarena.com/pics/15/05/project-tango-google-store/gsmarena_001.jpg\"><!--record-id-303-->Google Tango Development Kit</a><!--record-id-304-->
  6. src=\"https://www.youtube.com/embed/SkJG-uFU2yA?rel=0&showinfo=1&start=110\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><br record-id=\"320\"/><!--record-id-321-->\nТакой контент показался мне очень интересным; я решил поэкспериментировать с ним немного и написать своё приложение для генерации 4D роликов. Конечно, у меня нет студии и ресурсов как у Microsoft Research, да и сенсор всего один, поэтому результаты будут намного скромнее. Но это не остановит любителя программировать, правильно? О том, что у меня получилось, я и расскажу в этой статье.<br record-id=\"322\"/><!--record-id-323-->\n<br record-id=\"324\"/><!--record-id-325-->\n<div record-id=\"326\" class=\"spoiler\"><b record-id=\"327\" class=\"spoiler_title\"><!--record-id-328-->Про название статьи</b><div record-id=\"329\" class=\"spoiler_text\"><!--record-id-330-->Надо признать, название «4D видео» — не самое удачное. Первый же вопрос: почему «4D», а не «3D». Ведь обычное видео не называют трёхмерным только потому, что плоская картинка изменяется со временем. Действительно, в серьезных работах обычно используют термин «free viewpoint video». Но для заголовка это слишком скучно, и я решил оставить кликбейтное 4D (хотя до 11D кинотеатров ещё далеко).<br record-id=\"331\"/><!--record-id-332-->\n<div record-id=\"333\" class=\"img_wrapper\"><img record-id=\"334\" src=\"https://habrastorage.org/web/474/be5/c08/474be5c0846f47e28218bfa8462185ff.jpg\"/></div><br record-id=\"335\"/><!--record-id-336-->\n</div></div><br record-id=\"337\"/><!--record-id-338-->\nБольшая часть аудитории, несомненно, знакома с 3D сенсорами. Самый массовый девайс в этой категории — всем известный Kinect, очень успешный продукт компании Microsoft. Однако несмотря на относительную распространённость, для многих людей depth-сенсоры остаются чем-то диковинным. Нам же будет полезно разобраться с принципом их работы прежде чем начинать писать приложения.<br record-id=\"339\"/><!--record-id-340-->\n<br record-id=\"341\"/><!--record-id-342-->\nС Google Tango и другими structured light устройствами всё относительно понятно. Встроенный в девайс инфракрасный прожектор проецирует на сцену нерегулярный паттерн из световых точек, примерно как на этой картинке:<br record-id=\"343\"/><!--record-id-344-->\n<br record-id=\"345\"/><!--record-id-346-->\n<div record-id=\"347\" style=\"text-align:center;\"><div record-id=\"348\" class=\"img_wrapper\"><img record-id=\"349\" src=\"https://habrastorage.org/web/9e9/daa/a53/9e9daaa5327049d2ba1fb3ce8b9c3828.jpg\" width=\"480\"/></div></div><br record-id=\"350\"/><!--record-id-351-->\nЗатем специальный софт превращает искажения этого паттерна на изображении с ИК-камеры (вызванные разнообразной формой объектов) в серию 3D измерений. Для каждого световог
  7. было достигнуто: координаты точек записались в бинарный файл. На скриншоте показано как выглядит облако точек с одного кадра в программе Meshlab.<br record-id=\"368\"/><!--record-id-369-->\n<br record-id=\"370\"/><!--record-id-371-->\nОк, облака точек это уже интересно. Однако point cloud — весьма “разреженное” представление сцены, ведь разрешение современных structured light сенсоров довольно низкое (обычно в районе 100x100 точек, плюс-минус). Да и в целом, в мире компьютерной графики гораздо привычнее другое представление 3D объектов и сцен, а именно полигональные сетки, или меши. <br record-id=\"372\"/><!--record-id-373-->\n<br record-id=\"374\"/><!--record-id-375-->\nЕсли подумать, задача получения меша по облаку точек с одной 3D камеры довольно проста, значительно проще, чем произвольный meshing в 3D. Для этого нам не нужны никакие <a record-id=\"376\" href=\"https://en.wikipedia.org/wiki/Marching_cubes\"><!--record-id-377-->марширующие кубы</a><!--record-id-378--> или <a record-id=\"379\" href=\"http://www.cs.jhu.edu/~misha/Code/PoissonRecon/Version9.01/\"><!--record-id-380-->реконструкция Пуассона</a><!--record-id-381-->. Вспомним, что точки были получены с помощью одной единственной IR-камеры и естественным образом проецируются обратно на фокальную плоскость:<br record-id=\"382\"/><!--record-id-383-->\n<br record-id=\"384\"/><!--record-id-385-->\n<div record-id=\"386\" style=\"text-align:center;\"><div record-id=\"387\" class=\"img_wrapper\"><img record-id=\"388\" src=\"https://habrastorage.org/web/0eb/1dd/e9e/0eb1dde9e6514aa4b01f52479ea0d101.gif\"/></div></div><br record-id=\"389\"/><!--record-id-390-->\nТеперь мы можем решать задачу в 2D, забыв на время про Z-координату. Чтобы получить полигоны нужно всего лишь триангулировать множество точек на плоскости. Как только это сделано, мы проецируем вершины обратно в 3D используя <a record-id=\"391\" href=\"https://en.wikipedia.org/wiki/Pinhole_camera_model\"><!--record-id-392-->внутренние параметры</a><!--record-id-393--> IR-камеры и известную в каждой точке глубину. Триангуляция будет диктовать связность между вершинами, т.е. каждый треугольник мы интерпретируем как грань меша. Таким образом на каждом кадре получится настоящая 3D модель сцены, которую можно отрендерить в OpenGL, открыть в Blender и т.п.<br record-id=\"394\"/><!--record-id-395-->\n<br record-id=\"396\"/><!--record-id-397-->\nИтак, всё что осталось сделать — найти триангуляцию для точек на каждом кадре. Есть масса способов триангулировать множество точек в 2D, и по сути любая триангуляция даст нам какой-то меш. Но ровно один способ является оптимальным для построения полигональной сетки — триангуляция Делоне.<br record-id=\"398\"/><!--record-id-399-->\n<br record-id=\
  8. 0%B9%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B3%D1%80%D0%B0%D1%84\"><!--record-id-420-->двойственна </a><!--record-id-421-->диаграмме Вороного:<br record-id=\"422\"/><!--record-id-423-->\n<br record-id=\"424\"/><!--record-id-425-->\n<div record-id=\"426\" style=\"text-align:center;\"><div record-id=\"427\" class=\"img_wrapper\"><img record-id=\"428\" width=\"260\" src=\"https://habrastorage.org/web/ce4/7cd/e5b/ce47cde5b7ea45c69d62416da0d4d19c.png\"/></div></div><br record-id=\"429\"/><!--record-id-430-->\n<br record-id=\"431\"/><!--record-id-432-->\nТриангуляции Делоне обладают множеством замечательных свойств, но нам особенно интересны вот эти два:<br record-id=\"433\"/><!--record-id-434-->\n<br record-id=\"435\"/><!--record-id-436-->\n<ol record-id=\"437\"><!--record-id-438-->\n<li record-id=\"439\"><!--record-id-440-->Описанная около любого из треугольников окружность не содержит в себе точек множества, кроме вершин самого треугольника.</li><!--record-id-441-->\n<li record-id=\"442\"><!--record-id-443-->Триангуляция Делоне максимизирует минимальный угол среди всех углов всех треугольников, тем самым избегаются вырожденные и «тонкие» треугольники.</li><!--record-id-444-->\n</ol><br record-id=\"445\"/><!--record-id-446-->\nСвойство #2 достаточно интуитивно следует из #1. Действительно, чтобы описанные окружности не содержали посторонних точек, они должны быть по возможности небольшими, а радиус окружности для “тонких” треугольников (близких к вырожденным) наоборот очень велик. Таким образом триангуляция Делоне максимизирует количество “хороших” треугольников, далёких от вырожденных. А значит и наш меш должен выглядеть хорошо.<br record-id=\"447\"/><!--record-id-448-->\n<br record-id=\"449\"/><!--record-id-450-->\nСказано — сделано, пишем триангуляцию Делоне. Есть множество известных алгоритмов, <a record-id=\"451\" href=\"https://e-maxx.ru/algo/voronoi_diagram_2d_n4\"><!--record-id-452-->самые простые</a><!--record-id-453--> начинаются где-то с <math record-id=\"454\"></math><img record-id=\"455\" src=\"https://habrastorage.org/getpro/habr/formulas/8e3/e4b/3af/8e3e4b3af7c1321e593b77fb58c61afa.svg\" alt=\"$O(n^4)$\" data-tex=\"inline\"/><!--record-id-456-->. Но раз люди научились считать эти триангуляции за <math record-id=\"457\"></math><img record-id=\"458\" src=\"https://habrastorage.org/getpro/habr/formulas/e85/9e3/389/e859e33895fd579701b4da0969f53c18.svg\" alt=\"$O(nlogn)$\" data-tex=\"inline\"/><!--record-id-459-->, мы просто не можем быть медленнее!<br record-id=\"460\"/><!--record-id-461-->\n<br record-id=\"462\"/><!--record-id-463-->\nКак и во многих других подоб��ых задачах, алгоритм строится по принципу “разделяй и властвуй”. Будем сортировать точки по координатам x и y, а затем рекурсивно генерировать и объединять триангуляции пока не получится один большой граф. Достаточно показать вот этот кусочек кода, чтобы стало понятно, что здесь происходит:<br rec
  9. dx rre;  <span record-id=\"488\" class=\"hljs-comment\"><!--record-id-489-->// CW convex hull edge starting at the rightmost vertex of right triangulation</span><!--record-id-490-->\ntriangulateSubset(lIdx + numLeft, numRight, rle, rre);\ntriangulateSubset(lIdx, numLeft, lle, lre);\nmergeTriangulations(lle, lre, rle, rre, le, re);\n</code></pre><br record-id=\"491\"/><!--record-id-492-->\nВ принципе всё, можно расходиться :)<br record-id=\"493\"/><!--record-id-494-->\nНа самом деле нет, потому что самое интересное начинается в функции mergeTriangulations. Действительно, если мы разделили наше множество пополам достаточное число раз, мы остались с кусочками по две или три точки, с которыми мы как-нибудь разберёмся:<br record-id=\"495\"/><!--record-id-496-->\n<br record-id=\"497\"/><!--record-id-498-->\n<div record-id=\"499\" style=\"text-align:center;\"><img record-id=\"500\" width=\"240\" src=\"https://habrastorage.org/web/fd3/4c1/8a8/fd34c18a8e874103a40c365ddaec4fb7.gif\"/></div><br record-id=\"501\"/><!--record-id-502-->\nА что потом?<br record-id=\"503\"/><!--record-id-504-->\n<br record-id=\"505\"/><!--record-id-506-->\n<div record-id=\"507\" class=\"spoiler\"><b record-id=\"508\" class=\"spoiler_title\"><!--record-id-509-->Про иллюстрации</b><div record-id=\"510\" class=\"spoiler_text\"><!--record-id-511-->Здесь и далее я буду сопровождать описание GIF-анимациями, которые сгенерировала моя программа, а также иллюстрациями из одной хорошей статьи. При описании алгоритма я во многом буду повторять эту <a record-id=\"512\" href=\"http://www.geom.uiuc.edu/~samuelp/del_project.html\"><!--record-id-513-->статью</a><!--record-id-514-->, так что если возникнут вопросы можно смело с ней консультироваться.<br record-id=\"515\"/><!--record-id-516-->\n</div></div><br record-id=\"517\"/><!--record-id-518-->\nНа самом деле тоже ничего сложного. В каждом листе рекурсии мы уже получили валидное решение подзадачи. Осталось подняться вверх по стеку, по пути сливая левое и правое разбиение в единое целое. Но делать это нужно аккуратно, т.к. далеко не каждый способ слияния даст нам на выходе триангуляцию Делоне.<br record-id=\"519\"/><!--record-id-520-->\nАлгоритм Гибаса и Столфи предлагает весьма элегантное решение этой проблемы. Идея в том, чтобы воспользоваться свойством #1, которое я упомянул выше, но обо всём по порядку.<br record-id=\"521\"/><!--record-id-522-->\nСперва немного обозначений; давайте назовём левую триангуляцию L, а правую R. Тогда рёбра, принадлежащие левой триангуляции будем называть LL, т.к. они начинаются и заканчиваются в точках левого подмножества. Ребра правой триангуляции назовём RR, а рёбра, которые мы будем добавлять между левой и правой половиной — LR, точно как на иллюстрации:<br record-id=\"523\"/><!--record-id-524-->\n<br record-id=\"525\"/><!--record-id-526-->\n<div record-id=\"527\" style=\"text-align:center;\"><img record-id=\"528\" src=\"https://habrasto
  10. метим также, что при слиянии двух непересекающихся разбиений нам всегда нужно будет добавить ровно два новых ребра, чтобы достроить выпуклую оболочку объединённого множества (грубо говоря, “накрыть” точки новыми рёбрами сверху и снизу). Отлично, у нас уже есть два новых LR-ребра! Выберем одно из них, нижнее, и назовём его “базой” (в коде — base).<br record-id=\"537\"/><!--record-id-538-->\n<br record-id=\"539\"/><!--record-id-540-->\n<div record-id=\"541\" style=\"text-align:center;\"><img record-id=\"542\" src=\"https://habrastorage.org/web/9f5/ec4/e19/9f5ec4e19ac842928c7c512c0a8864c0.gif\"/></div><br record-id=\"543\"/><!--record-id-544-->\nТеперь мы должны добавить следующее ребро, смежное с base, при этом один из его концов совпадает с концом base, а другим концом является точка либо из L, либо из R. Собственно, нам и нужно решить какой из двух вариантов является правильным. Начнём с правой стороны. Первым кандидатом будет точка, связанная с правым концом base RR-ребром с наименьшим углом по часовой стрелке относительно base. Следующими по очереди кандидатами будут точки R, соединённые с правой вершиной base RR-рёбрами с увеличивающимся значением угла относительно base, как показано на иллюстрации:<br record-id=\"545\"/><!--record-id-546-->\n<br record-id=\"547\"/><!--record-id-548-->\n<div record-id=\"549\" style=\"text-align:center;\"><img record-id=\"550\" src=\"https://habrastorage.org/web/8ae/9f7/71d/8ae9f771d94746b99bbe327b8adcb7d4.gif\"/></div><br record-id=\"551\"/><!--record-id-552-->\nТеперь для каждого кандидата нужно проверить два условия:<br record-id=\"553\"/><!--record-id-554-->\n<br record-id=\"555\"/><!--record-id-556-->\n<ol record-id=\"557\"><!--record-id-558-->\n<li record-id=\"559\"><!--record-id-560-->Угол между base и кандидатом не должен превышать 180 градусов (нас интересуют только те точки, что “выше” base).</li><!--record-id-561-->\n<li record-id=\"562\"><!--record-id-563-->Окружность, описанная вокруг base и точки-кандидата не должна содержать в себе следующую точку-кандидат.</li><!--record-id-564-->\n</ol><br record-id=\"565\"/><!--record-id-566-->\n<div record-id=\"567\" style=\"text-align:center;\"><img record-id=\"568\" src=\"https://habrastorage.org/web/379/d5e/1a7/379d5e1a72174becb64f991f0b3455fc.gif\"/></div><br record-id=\"569\"/><!--record-id-570-->\nВ зависимости от конфигурации вершин здесь может быть несколько вариантов:<br record-id=\"571\"/><!--record-id-572-->\n<ul record-id=\"573\"><!--record-id-574-->\n<li record-id=\"575\"><!--record-id-576-->Нашлась точка-кандидат, которая удовлетворяет обоим критериям. Отлично, это и будет наш выбор для правой стороны.</li><!--record-id-577-->\n<li record-id=\"578\"><!--record-id-579-->Если не выполняется требование #1 (угол &lt; 180 градусов), значит мы уже достигли “верха”, и более нет необходимости выбирать точки с прав�
  11. ияние и нужно подниматься дальше по стеку. Если нашлась одна точка (только слева или только справа), мы добавляем LR-ребро с концом в ней. Если точки нашлись с обеих сторон, мы повторяем тест с окружностью: строим описанную окружность вокруг base и точки-кандидата из L и R. Выбираем ту точку, чья окружность не содержит кандидата из противоположной половины. Факт: такая точка всегда будет единственной, если только четыре вершины не образуют прямоугольник. В этом случае можно выбрать любой из вариантов.<br record-id=\"598\"/><!--record-id-599-->\n<br record-id=\"600\"/><!--record-id-601-->\n<div record-id=\"602\" style=\"text-align:center;\"><img record-id=\"603\" src=\"https://habrastorage.org/web/232/c88/5ec/232c885ec6384eb7a3e8422e4139ab7e.gif\"/></div><br record-id=\"604\"/><!--record-id-605-->\nВ данном примере мы выбираем кандидата из L, потому что соответствующая окружность не содержит точку-кандидата из R. <br record-id=\"606\"/><!--record-id-607-->\nПосле того как новое LR-ребро добавлено, оно становится новой “базой” (base). Повторяем обновление base пока не достигнем верхнего ребра выпуклой оболочки:<br record-id=\"608\"/><!--record-id-609-->\n<br record-id=\"610\"/><!--record-id-611-->\n<div record-id=\"612\" style=\"text-align:center;\"><img record-id=\"613\" src=\"https://habrastorage.org/web/ad8/0b5/218/ad80b521856f48fa9a87b46fc6a15a71.gif\"/></div><br record-id=\"614\"/><!--record-id-615-->\nОказывается, если наш алгоритм будет аккуратно следовать описанным правилам, то после слияния левой и правой половины мы получим валидную триангуляцию Делоне для L∪R.<br record-id=\"616\"/><!--record-id-617-->\n”Я нашёл этому поистине чудесное доказательство, но поля данной книги слишком узки для него.” :) На самом деле, если вам интересно, откуда взялись все утверждения, например про необходимость удаления рёбер, рекомендую исследовать <a record-id=\"618\" href=\"http://www.sccg.sk/~samuelcik/dgs/quad_edge.pdf\"><!--record-id-619-->работу Гибаса и Столфи</a><!--record-id-620-->, ключевые леммы под номерами 9.2, 9.3, 9.4, 8.3.<br record-id=\"621\"/><!--record-id-622-->\n<br record-id=\"623\"/><!--record-id-624-->\nЧто ж, теперь соберём всё вместе и посмотрим что получится:<br record-id=\"625\"/><!--record-id-626-->\n<br record-id=\"627\"/><!--record-id-628-->\n<div record-id=\"629\" style=\"text-align:center;\"><img record-id=\"630\" src=\"https://habrastorage.org/web/b4b/621/55a/b4b62155a8834025859113e5181236af.gif\"/></div><br record-id=\"631\"/><!--record-id-632-->\nЭто визуализация работы алгоритма, который у меня получился. Здесь оранжевым отмечено ребро base, зелёным — LL-кандидат, синим — RR-кандидат. Красным помечены рёбра, которые не удовлетворяют критерию #2 и будут удалены.<br record-id=\"633\"/><!--record-id-634-->\n<br record-id=\"635\"/><!--record-id-636-->\nПока опис
  12. astorage.org/getpro/habr/formulas/e85/9e3/389/e859e33895fd579701b4da0969f53c18.svg\" alt=\"$O(nlogn)$\" data-tex=\"inline\"/><!--record-id-648--> и близка к линейной; нужен какой-нибудь особенно больной датасет, чтобы заставить алгоритм перестраивать триангуляцию с нуля на каждой стадии слияния.<br record-id=\"649\"/><!--record-id-650-->\nЕщё одно замечание — из полученной триангуляции легко получить и выпуклую оболочку, и диаграмму Вороного для соответствующего множества точек. Приятный бонус.<br record-id=\"651\"/><!--record-id-652-->\n<br record-id=\"653\"/><!--record-id-654-->\nИнтересно сказать пару слов про структуру данных, которую я использовал для работы с графом. Обычно графы представляют как списки или матрицы смежности, но в данной задаче нас интересует не только связность, но и некоторые геометрические свойства графа. Вот что у меня получилось:<br record-id=\"655\"/><!--record-id-656-->\n<br record-id=\"657\"/><!--record-id-658-->\n<pre record-id=\"659\"><code record-id=\"660\" class=\"cpp hljs\"><span record-id=\"661\" class=\"hljs-keyword\"><!--record-id-662-->struct</span><!--record-id-663--> TriEdge\n{\n    <span record-id=\"664\" class=\"hljs-keyword\"><!--record-id-665-->uint16_t</span><!--record-id-666--> origPnt;  <span record-id=\"667\" class=\"hljs-comment\"><!--record-id-668-->// index of edge's origin point</span><!--record-id-669-->\n    EdgeIdx symEdge;  <span record-id=\"670\" class=\"hljs-comment\"><!--record-id-671-->// index of pair edge, with same endpoints and opposite direction</span><!--record-id-672-->\n    EdgeIdx nextCcwEdge;  <span record-id=\"673\" class=\"hljs-comment\"><!--record-id-674-->// next counterclockwise (CCW) edge around the origin</span><!--record-id-675-->\n    EdgeIdx prevCcwEdge;  <span record-id=\"676\" class=\"hljs-comment\"><!--record-id-677-->// previous CCW edge around the origin (or next CW edge)</span><!--record-id-678-->\n};</code></pre><br record-id=\"679\"/><!--record-id-680-->\nЭто в некотором роде урезанная версия структуры, которую предлагают Гибас и Столфи. Как говорится, всё гениальное просто. Для каждого ребра мы храним точку, из которой оно “выходит” (origin), индекс его парного ребра, направленного в противоположную сторону, а также индексы следующего и предыдущего ребра “вокруг” origin-точки. По сути получается двусвязный список, но так как мы поддерживаем относительное расположение рёбер вокруг их концов, многие шаги алгоритма кодируются просто элементарно.<br record-id=\"681\"/><!--record-id-682-->\nВ <a record-id=\"683\" href=\"https://www.cs.cmu.edu/~quake/triangle.html\"><!--record-id-684-->некоторых других работах</a><!--record-id-685--> предлагается хранить не рёбра, а сразу треугольники. Я пробовал экспериментировать с таким вариантом, и могу сказать, что объем кода вырастает в разы, т.к. приходится вводить многочисленные костыли для особых случаев (вырожденные треугольники, точки на бе
  13. ть никакие рёбра. Но так бывает не всегда.<br record-id=\"702\"/><!--record-id-703-->\n<div record-id=\"704\" style=\"text-align:center;\"><img record-id=\"705\" src=\"https://habrastorage.org/web/b83/a96/f64/b83a96f643824c8aa4fe61f21a9ae3e2.gif\"/></div><br record-id=\"706\"/><!--record-id-707-->\nУже интереснее. Количество точек на стороне решётки стало нечётным и из-за этого алгоритм вынужден делать довольно много исправлений. Как насчёт окружности из точек?<br record-id=\"708\"/><!--record-id-709-->\n<br record-id=\"710\"/><!--record-id-711-->\n<div record-id=\"712\" style=\"text-align:center;\"><img record-id=\"713\" src=\"https://habrastorage.org/web/817/3e1/fe3/8173e1fe350243c8b80f9003b26e4818.gif\"/></div><br record-id=\"714\"/><!--record-id-715-->\nИнтересно! Но мне больше нравится с точкой в центре:<br record-id=\"716\"/><!--record-id-717-->\n<br record-id=\"718\"/><!--record-id-719-->\n<div record-id=\"720\" style=\"text-align:center;\"><img record-id=\"721\" src=\"https://habrastorage.org/web/934/43a/711/93443a7116b84070a14eaa70a5007311.gif\"/></div><br record-id=\"722\"/><!--record-id-723-->\n<br record-id=\"724\"/><!--record-id-725-->\nЯ думаю, к этому моменту статья содержит достаточное количество GIF-анимаций. Чтобы у читателей с <a record-id=\"726\" href=\"https://geektimes.ru/post/290377/\"><!--record-id-727-->ограничениями по трафику</a><!--record-id-728--> осталось хоть немного интернета после загрузки этой статьи, я залил остальные анимации на видео-хостинг.<br record-id=\"729\"/><!--record-id-730-->\n<strong record-id=\"731\"><!--record-id-732-->Рекомендуется залипать в 1080p и 60fps, это оригинальное разрешение видео. Причём лучше развернуть на весь экран, иначе рёбра графа получаются алиасными.</strong><br record-id=\"733\"/><!--record-id-734-->\n<br record-id=\"735\"/><!--record-id-736-->\n<div record-id=\"737\" class=\"oembed\"><div record-id=\"738\"><div record-id=\"739\" style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.2493%;\"><iframe record-id=\"740\" src=\"https://www.youtube.com/embed/G3US_HTZ1-o?rel=0&showinfo=1\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><br record-id=\"741\"/><!--record-id-742-->\nЯ осознаю, что эти видео интересны далеко не всем, но на меня они производят такой же эффект, как заставка “трубопровод” в старых версиях Windows. Оторваться сложно.<br record-id=\"743\"/><!--record-id-744-->\n<br record-id=\"745\"/><!--record-id-746-->\n<div record-id=\"747\" class=\"oembed\"><div record-id=\"748\"><div record-id=\"749\" style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.2493%;\"><iframe record-id=\"750\" src=\"https://www.youtube.com/embed/6WLeexsfNCg?rel=0&showinfo=1\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><br record-id=\"751\"/><!--record-id-752-->\nЭти анимации стали главной причиной, почему статья писалась так долго. Note to self: в следующий раз обойтись дебаггером и трейсами, делать дебажные визуализации опасно :) Если кто-то хочет посмотреть на работу алг�
  14. вспомнить для чего изначально создавался алгоритм. Мы собирались генерировать полигональный меш из данных с depth-сенсора. Что ж, давайте возьмём облако точек с сенсора, спроецируем на плоскость камеры и запустим алгоритм триангуляции.<br record-id=\"765\"/><!--record-id-766-->\n<br record-id=\"767\"/><!--record-id-768-->\n<div record-id=\"769\" class=\"oembed\"><div record-id=\"770\"><div record-id=\"771\" style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.2493%;\"><iframe record-id=\"772\" src=\"https://www.youtube.com/embed/-qH7y5U7ycE?rel=0&showinfo=1\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><!--record-id-773-->(Не спрашивайте меня сколько рендерился этот ролик. Бедный ffmpeg.)<br record-id=\"774\"/><!--record-id-775-->\n<br record-id=\"776\"/><!--record-id-777-->\nИтак, отлично! Хотя на данном этапе у нас есть только граф из точек и рёбер, из него элементарным образом можно сгенерировать массив треугольников. Осталось только отфильтровать некрасивые полигоны вытянутые по Z-координате, которые возникают на границах объектов и сделать простой проигрыватель на OpenGL:<br record-id=\"778\"/><!--record-id-779-->\n<br record-id=\"780\"/><!--record-id-781-->\n<div record-id=\"782\" class=\"oembed\"><div record-id=\"783\"><div record-id=\"784\" style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.2493%;\"><iframe record-id=\"785\" src=\"https://www.youtube.com/embed/bf1bJuOdQ6k?rel=0&showinfo=1\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><br record-id=\"786\"/><!--record-id-787-->\nЗдесь хорошо видно, что первая версия граббера была очень сырой: половина кадров не успели записаться, из-за этого картинка замирает. Короче, едва ли режиссёрский шедевр. Но это не важно — алгоритмы наконец-то ожили! Для меня это было настоящее “Прибытие поезда”!<br record-id=\"788\"/><!--record-id-789-->\n<br record-id=\"790\"/><!--record-id-791-->\nПосле этого я снял ещё пару роликов, я залил их на ресурс Sketchfab в формате timeframe animation, мне кажется так будет интереснее.<br record-id=\"792\"/><!--record-id-793-->\n<br record-id=\"794\"/><!--record-id-795-->\n<a record-id=\"796\" href=\"https://skfb.ly/6soGq\"><!--record-id-797-->Датасет #2 в WebGL</a><br record-id=\"798\"/><!--record-id-799-->\n<a record-id=\"800\" href=\"https://skfb.ly/6soGr\"><!--record-id-801-->Датасет #3 в WebGL</a><br record-id=\"802\"/><!--record-id-803-->\n<br record-id=\"804\"/><!--record-id-805-->\nЧто ж, пайплайн заработал и стало ясно, что дальнейшее развитие ограничивают возможности железа. Действительно, планшет Tango позволяет снимать только с очень низкой частотой кадров (5 fps), а ведь основная идея была в том, чтобы запечатлеть динамический характер сцен. Есть ещё одно существенное ограничение: в Tango не �
  15. deo/blob/master/src/libs/realsense/src/realsense_grabber.cpp\"><!--record-id-812-->C++</a><!--record-id-813-->, а не на Java) и продолжить эксперименты.<br record-id=\"814\"/><!--record-id-815-->\n<br record-id=\"816\"/><!--record-id-817-->\nСразу же выяснилось, что с моим пайплайном есть небольшая проблема. С увеличенным разрешением и высокой частотой съемки, которую позволяет R200, производительности уже не хватало, чтобы генерировать меш на каждом кадре в реалтайме. Профилировка показала, что узкое место — это конечно же триангуляция. Первоначальная версия была написана достаточно “расслабленно”, с динамическим выделением памяти, использованием STL и т.п. Кроме того, первая версия работала с координатами типа float, хотя в моей задаче точки всегда имеют целочисленные координаты (позиции в пикселях на картинке). Так что неудивительно, что хороший с точки зрения асимптотики алгоритм работал на моём ноутбуке до 30 миллисекунд на тестовом кадре с Tango (около 12000 точек). Потенциал для ускорения был очевиден и я увлечённо засел оптимизировать. Развивались события как-то так:<br record-id=\"818\"/><!--record-id-819-->\n<br record-id=\"820\"/><!--record-id-821-->\n<ul record-id=\"822\"><!--record-id-823-->\n<li record-id=\"824\"><!--record-id-825-->Первым делом на алтарь скорости отправились числа с плавающей точкой. Все алгоритмы (где это возможно) перешли на целочисленные вычисления.</li><!--record-id-826-->\n<li record-id=\"827\"><!--record-id-828-->Вторым на очереди было динамическое выделение памяти. Теперь вся память для алгоритма выделялась один раз, “на худший случай”, и затем переиспользовалась. Не самое эффективное решение с точки зрения потребления памяти (в духе ACM ICPC), но это дало значительное ускорение.</li><!--record-id-829-->\n<li record-id=\"830\"><!--record-id-831-->На сайте проекта посвящённого численной симуляции землетрясений был найден замечательный <a record-id=\"832\" href=\"https://www.cs.cmu.edu/~quake/robust.html\"><!--record-id-833-->тест</a><!--record-id-834--> на нахождение точки внутри описанной окружности треугольника: <br record-id=\"835\"/><!--record-id-836-->\n<br record-id=\"837\"/><!--record-id-838-->\nВот его реализация:<br record-id=\"839\"/><!--record-id-840-->\n<pre record-id=\"841\"><code record-id=\"842\" class=\"cpp hljs\"><span record-id=\"843\" class=\"hljs-function\"><!--record-id-844-->FORCE_INLINE <span record-id=\"845\" class=\"hljs-keyword\"><!--record-id-846-->bool</span><!--record-id-847--> <span record-id=\"848\" class=\"hljs-title\"><!--record-id-849-->inCircle</span><span record-id=\"850\" class=\"hljs-params\"><!--record-id-851-->(<span record-id=\"852\" class=\"hljs-keyword\"><!--record-id-853-->int</span><!--record-id-854--> x1, <span record-id=\"855\" class=\"hljs-keyword\"><!--record-id-856-->int</span><!--record-id-857--> y1, <span record-i
  16. -id-888-->int</span><!--record-id-889--> p1p_x = x1 - px;\n    <span record-id=\"890\" class=\"hljs-keyword\"><!--record-id-891-->const</span><!--record-id-892--> <span record-id=\"893\" class=\"hljs-keyword\"><!--record-id-894-->int</span><!--record-id-895--> p1p_y = y1 - py;\n\n    <span record-id=\"896\" class=\"hljs-keyword\"><!--record-id-897-->const</span><!--record-id-898--> <span record-id=\"899\" class=\"hljs-keyword\"><!--record-id-900-->int</span><!--record-id-901--> p2p_x = x2 - px;\n    <span record-id=\"902\" class=\"hljs-keyword\"><!--record-id-903-->const</span><!--record-id-904--> <span record-id=\"905\" class=\"hljs-keyword\"><!--record-id-906-->int</span><!--record-id-907--> p2p_y = y2 - py;\n\n    <span record-id=\"908\" class=\"hljs-keyword\"><!--record-id-909-->const</span><!--record-id-910--> <span record-id=\"911\" class=\"hljs-keyword\"><!--record-id-912-->int</span><!--record-id-913--> p3p_x = x3 - px;\n    <span record-id=\"914\" class=\"hljs-keyword\"><!--record-id-915-->const</span><!--record-id-916--> <span record-id=\"917\" class=\"hljs-keyword\"><!--record-id-918-->int</span><!--record-id-919--> p3p_y = y3 - py;\n\n    <span record-id=\"920\" class=\"hljs-keyword\"><!--record-id-921-->const</span><!--record-id-922--> <span record-id=\"923\" class=\"hljs-keyword\"><!--record-id-924-->int64_t</span><!--record-id-925--> p1p = p1p_x * p1p_x + p1p_y * p1p_y;\n    <span record-id=\"926\" class=\"hljs-keyword\"><!--record-id-927-->const</span><!--record-id-928--> <span record-id=\"929\" class=\"hljs-keyword\"><!--record-id-930-->int64_t</span><!--record-id-931--> p2p = p2p_x * p2p_x + p2p_y * p2p_y;\n    <span record-id=\"932\" class=\"hljs-keyword\"><!--record-id-933-->const</span><!--record-id-934--> <span record-id=\"935\" class=\"hljs-keyword\"><!--record-id-936-->int64_t</span><!--record-id-937--> p3p = p3p_x * p3p_x + p3p_y * p3p_y;\n\n    <span record-id=\"938\" class=\"hljs-comment\"><!--record-id-939-->// determinant of matrix, see paper for the reference</span><!--record-id-940-->\n    <span record-id=\"941\" class=\"hljs-keyword\"><!--record-id-942-->const</span><!--record-id-943--> <span record-id=\"944\" class=\"hljs-keyword\"><!--record-id-945-->int64_t</span><!--record-id-946--> res = p1p_x * (p2p_y * p3p - p2p * p3p_y)\n                      - p1p_y * (p2p_x * p3p - p2p * p3p_x)\n                      + p1p * (p2p_x * p3p_y - p2p_y * p3p_x);\n\n    assert(<span record-id=\"947\" class=\"hljs-built_in\"><!--record-id-948-->std</span><!--record-id-949-->::<span record-id=\"950\" class=\"hljs-built_in\"><!--record-id-951-->abs</span><!--record-id-952-->(res) &lt; <span record-id=\"953\" class=\"hljs-built_in\"><!--record-id-954-->std</span><!--record-id-955-->::numeric_limits&lt;int64>::max() / <span record-id=\"956\" class=\"hljs-number\"><!--record-id-957-->100</span><!--record-id-958-->);\n\n    <span record-id=\"959\" class=\"hljs-keyword\"><!--record-id-960-->return</span><!--record-id-961--> res &lt; <span record-id=\"962\" class=\"hljs-number\"><!--record-id-963-->0</span><!--record-id-964-->;\n}</code></pre></li><!--record-id-965-->\n</ul><br record-id=\"966\"/><!--record-id-967-->\nЭти три мероприятия дали очень значительное ускорение, с 30000+ до 6100 микросекунд на кадр. Но можно было ускорить ещё:<br record-id=\"968\"/><!--record-id-969-->\n<br record-id=\"970\"/><!--record-id-971-->\n<ul record-id=\"972\"><!--record-id-973-->\n<li record-id=\"974\"><!--record-id-975-->Сделал некоторым небольшим функциям __forceinline, 6100 -> 5700 микросекунд, редкий случай когда компилятор сам не догадался. </li><!--record-id-976-->\n<li record-id=\"977\"><!--record-id-978-->Удалил #pragma pack(push, 1) для стуктуры TriEdge. И почему я решил, что с запаковкой будет быстрее? 5700 -> 4800 микросекунд.</li><!--record-
  17. br record-id=\"983\"/><!--record-id-984-->\nИтого получилось ускорить код почти в 10 раз, и я думаю это не предел. Кстати, я не поленился собрать код для Android, и на схожей задаче ARM процессор Tango работал около 10 миллисекунд на кадр, т.е. 100 fps! Короче, получился даже немного overkill, но если кому-то нужна очень быстрая “целочисленная” триангуляция Делоне, то добро пожаловать в репозиторий.<br record-id=\"985\"/><!--record-id-986-->\n<br record-id=\"987\"/><!--record-id-988-->\nТеперь мои алгоритмы были готовы к R200, и вот первый датасет, который я снял:<br record-id=\"989\"/><!--record-id-990-->\n<br record-id=\"991\"/><!--record-id-992-->\n<div record-id=\"993\" class=\"oembed\"><div record-id=\"994\"><div record-id=\"995\" style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 75.0019%;\"><iframe record-id=\"996\" src=\"https://www.youtube.com/embed/7gJUIYt-Lew?rel=0&showinfo=1\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><br record-id=\"997\"/><!--record-id-998-->\n<br record-id=\"999\"/><!--record-id-1000-->\nЗа ним, естественно, последовали другие. Не буду прикладывать видео моего OpenGL viewer’а, по-моему интереснее смотреть сразу на Sketchfab: <a record-id=\"1001\" href=\"https://skfb.ly/6s6Ar\"><!--record-id-1002-->skfb.ly/6s6Ar</a><br record-id=\"1003\"/><!--record-id-1004-->\n<br record-id=\"1005\"/><!--record-id-1006-->\nРекомендуется открывать не больше одного ролика за раз, т.к. Sketchfab грузит в память сразу все кадры датасета, и вообще viewer у них не очень быстрый. Кстати, вот обещанный 4D котик (Вася):<br record-id=\"1007\"/><!--record-id-1008-->\n<br record-id=\"1009\"/><!--record-id-1010-->\n<ul record-id=\"1011\"><!--record-id-1012-->\n<li record-id=\"1013\"><a record-id=\"1014\" href=\"https://skfb.ly/6s6AC\"><!--record-id-1015-->skfb.ly/6s6AC</a></li><!--record-id-1016-->\n<li record-id=\"1017\"><a record-id=\"1018\" href=\"https://skfb.ly/6s6AJ\"><!--record-id-1019-->skfb.ly/6s6AJ</a></li><!--record-id-1020-->\n</ul><br record-id=\"1021\"/><!--record-id-1022-->\nПёс Тотошка был не очень счастлив, что на него светят лазером. Но выбора у него не было:<br record-id=\"1023\"/><!--record-id-1024-->\n<br record-id=\"1025\"/><!--record-id-1026-->\n<ul record-id=\"1027\"><!--record-id-1028-->\n<li record-id=\"1029\"><a record-id=\"1030\" href=\"https://skfb.ly/6s6AP\"><!--record-id-1031-->skfb.ly/6s6AP</a></li><!--record-id-1032-->\n<li record-id=\"1033\"><a record-id=\"1034\" href=\"https://skfb.ly/6s6BH\"><!--record-id-1035-->skfb.ly/6s6BH</a></li><!--record-id-1036-->\n</ul><br record-id=\"1037\"/><!--record-id-1038-->\nЕщё несколько роликов есть в моём аккаунте на Sketchfab. Конечно, качество моделей можно улучшить если тщательно отфильтровать шумы от сенсора, можно уменьшить количество точек, чтобы проигрыватель на сайте не так тормозил, и т.п. Но как говорится, нет предела совершенству; я и так потратил на этот pet project много времени :)<br record-id=\"1039\"/><!--record-id-1040-->\nДа и вообще, учитывая агрессивное наступление AR и VR,
  18. ght: 0; position: relative; padding-bottom: 56.2493%;\"><iframe record-id=\"1058\" src=\"https://www.youtube.com/embed/SH3MKjwgI80?rel=0&showinfo=1&start=99\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen=\"\" scrolling=\"no\"></iframe></div></div></div><br record-id=\"1059\"/><!--record-id-1060-->\nСогласитесь, выглядит весьма впечатляюще! В общем, за будущее free-viewpoint video переживать не приходится.<br record-id=\"1061\"/><!--record-id-1062-->\n<br record-id=\"1063\"/><!--record-id-1064-->\nНапоследок нужно сказать, что весь код написанный для этого проекта доступен на <a record-id=\"1065\" href=\"https://github.com/alex-petrenko/4dvideo\"><!--record-id-1066-->Github</a><!--record-id-1067--> под свободной лицензией. Хотя сгенерированные 4D ролики получились едва ли впечатляющими, у алгоритмов всё равно есть потенциал для дальнейшего использования и развития.<br record-id=\"1068\"/><!--record-id-1069-->\nГлавное преимущество описанного в статье подхода состоит в том, что 3D сцена генерируется на лету в realtime, в самом проигрывателе. Из-за этого в сжатом виде ролики могут занимать очень мало места, по сути почти столько же, сколько аналогичное традиционное видео. <br record-id=\"1070\"/><!--record-id-1071-->\n<br record-id=\"1072\"/><!--record-id-1073-->\nДействительно, обычное RGB видео нужно нам только для текстур, а 3D координаты точек можно сохранять как разреженные карты глубины и тоже кодировать в видео-файл, уже в grayscale. Таким образом, для рендеринга одного кадра в 3D нам нужны только кадры из двух видео и немного метаданных (параметры камеры, и т.п.). На основе этого можно сделать прикольное приложение, скажем, Skype в augmented reality. Собеседника снимает depth-камера, а ваш iPhone в реальном времени рендерит говорящую 3D голову с помощью ARKit. Почти как голограммы из Star Wars.<br record-id=\"1074\"/><!--record-id-1075-->\n<br record-id=\"1076\"/><!--record-id-1077-->\nЕсть ещё вариант, который может пригодиться пользователям Tango. Дело в том, что Tango SDK предоставляет данные в виде облаков точек в 3D (как я и описывал выше), при этом для многих алгоритмов хочется иметь плотную карту глубины (depth map). Самый распространённый способ её получения — спроецировать точки на фокальную плоскость и проинтерполировать значения глубины между соседними точками, в которых оно известно. Так вот комбинация триангуляции Делоне + OpenGL позволяет делать эту интерполяцию точно и эффективно. За счёт того, что растеризация происходит на GPU, можно генерировать карты глубины в высоком разрешении даже на смартфоне.<br record-id=\"1078\"/><!--record-id-1079-->\n<br record-i
  19. record-id-1113--> </li><!--record-id-1114-->\n</ul></div><!--record-id-1115-->\n    <!--record-id-1117-->\n\n    <div record-id=\"1118\" class=\"post_additionals\"><!--record-id-1119-->\n      <div record-id=\"1120\" class=\"bottom_buttons_panel panel_vote\" id=\"voting-wjt_333532\"><!--record-id-1121-->\n  <div record-id=\"1122\" class=\"label\"><!--record-id-1123-->Проголосовать:</div><!--record-id-1124-->\n      <div record-id=\"1125\" class=\"voting-wjt voting-wjt_mobile js-voting  \"><!--record-id-1126-->\n          <button record-id=\"1127\" type=\"button\" class=\"voting-wjt__button voting-wjt__button_plus voting-wjt__button_disabled\" data-message=\"Голосовать могут только зарегистрированные пользователи. \"><!--record-id-1128-->\n            <svg record-id=\"1129\" class=\"icon-svg icon-svg_arrow-up\" aria-hidden=\"true\" aria-labelledby=\"title\" version=\"1.1\" role=\"img\" width=\"15\" height=\"24\" viewBox=\"0 0 15 24\"><path record-id=\"1130\" d=\"M6.802.129l-6.709 7.637c-.211.241-.037.615.289.615h3.629c.21 0 .38.167.38.372v14.875c0 .205.169.372.379.372h4.64c.21 0 .379-.167.379-.372v-14.876c0-.205.17-.372.38-.372h3.63c.325 0 .5-.373.289-.615l-6.709-7.637c-.153-.171-.427-.171-.578.001z\"></path></svg><!--record-id-1131-->\n          </button><!--record-id-1132-->\n\n        <div record-id=\"1133\" class=\"voting-wjt__counter voting-wjt__counter_post  voting-wjt__counter_positive  js-mark\"><!--record-id-1134-->\n            <span record-id=\"1135\" class=\"voting-wjt__counter-score js-score\" title=\"Общий рейтинг 79: ↑78 и ↓1\"><!--record-id-1136-->+77</span><!--record-id-1137-->\n        </div><!--record-id-1138-->\n\n          <button record-id=\"1139\" type=\"button\" class=\"voting-wjt__button voting-wjt__button_minus voting-wjt__button_disabled\" data-message=\"Голосовать могут только зарегистрированные пользователи. \"><!--record-id-1140-->\n            <svg record-id=\"1141\" class=\"icon-svg icon-svg_arrow-down\" aria-hidden=\"true\" aria-labelledby=\"title\" version=\"1.1\" role=\"img\" width=\"15\" height=\"24\" viewBox=\"0 0 15 24\"><path record-id=\"1142\" d=\"M14.574 16.233c.211-.241.037-.615-.289-.615h-3.629c-.21 0-.38-.167-.38-.372v-14.875c0-.205-.169-.372-.379-.372h-4.64c-.21 0-.379.167-.379.372v14.876c0 .205-.17.372-.38.372h-3.63c-.325 0-.5.373-.289.615l6.709 7.637c.153.171.427.171.578-.001l6.709-7.637z\"></path></svg><!--record-id-1143-->\n          </button><!--record-id-1144-->\n      </div><!--record-id-1145-->\n</div><!--record-id-1146-->\n      <div record-id=\"1147\" class=\"bottom_buttons_panel panel_share\"><!--record-id-1148-->\n  <div record-id=\"1149\" class=\"share_to\"><!--record-id-1150-->\n    <div record-id=\"1151\" class=\"label\"><!--record-id-1152-->Поделиться:</div><!--record-id-1153-->\n    <div record-id=\"1154\" class=\"share_buttons\"><!--record-id-1155-->\n      <a record-id=\"1156\" href=\"https://www.facebook.com/sharer/sharer.php?u=https://habrahabr.ru/post/333532/?mobile=no\" title=\"Опубликовать ссылку в Facebook\" onclick=\"window.open(this.href, 'Опубликовать ссылку в Facebook', 'width=640,height=436,toolbar=0,status=0'); return false\" class=\"fb\"></a><!--record-id-1157-->\n        <a record-id=\"1158\" href=\"https://twitter.com/intent/tweet?text=Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне+https://habrahabr.ru/post/333532/?mobile=no+via+%40habrahabr\" title=\"Опубликовать ссылку в Twitter\" class=\"tw\" onclick=\"window.open(this.href, 'Опубликовать ссылку  в Twitter', 'width=800,height=300,resizable=yes,toolbar=0,status=0'); return false\"></a><!--record-id-1159-->\n      <a record-id=\"1160\" href=\"https://vk.com/share.php?url=https://habrahabr.ru/post/333532/?mobile=no\" title=\"Опубликовать ссылку во ВКонт
  20. d-id=\"1164\" class=\"save_to\"><!--record-id-1165-->\n    <div record-id=\"1166\" class=\"label\"><!--record-id-1167-->Сохранить:</div><!--record-id-1168-->\n    <div record-id=\"1169\" class=\"save_buttons\"><!--record-id-1170-->\n      \n      <a record-id=\"1171\" href=\"https://getpocket.com/edit?url=https://habrahabr.ru/post/333532/?mobile=no\" target=\"_blank\" title=\"Сохранить в Pocket\" class=\"pocket pocket-btn\"></a><!--record-id-1172-->\n    </div><!--record-id-1173-->\n  </div><!--record-id-1174-->\n</div><!--record-id-1175-->\n    </div><!--record-id-1176-->\n\n      <div record-id=\"1177\" class=\"buttons\"><!--record-id-1178-->\n          <a record-id=\"1179\" href=\"https://m.habrahabr.ru/post/333532/comments/\" class=\"btn btn-wide\"><!--record-id-1180-->\n              Комментарии (14)\n          </a><!--record-id-1181-->\n      </div><!--record-id-1182-->\n  </div><!--record-id-1183-->\n\n  <div record-id=\"1184\" class=\"banner_header\"><!--record-id-1185-->\n  <!--record-id-1186--><!--  AdRiver code START. Type:AjaxJS Site: m.habr BN:2 --><!--record-id-1187-->\n  <div record-id=\"1188\" id=\"adriver_banner_632548472\" style=\"margin: 0 auto;\" title=\"\"></div><!--record-id-1189-->\n  <!--record-id-1191-->\n  <!--record-id-1192--><!--  AdRiver code END  --><!--record-id-1193-->\n</div><!--record-id-1194-->\n\n\n  \n\n    <div record-id=\"1195\" class=\"similar_posts\"><!--record-id-1196-->\n      <div record-id=\"1197\" class=\"title\"><!--record-id-1198-->Похожие публикации</div><!--record-id-1199-->\n      <div record-id=\"1200\" class=\"posts\"><!--record-id-1201-->\n          <div record-id=\"1202\" class=\"post\"><!--record-id-1203-->\n              <a record-id=\"1204\" href=\"https://m.habrahabr.ru/post/311502/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_similar_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1205-->\n                <h3 record-id=\"1206\" class=\"title\"><!--record-id-1207-->Как я читал показания датчиков через SNMP (Python+AgentX+systemd+Raspberry Pi) и соорудил ещё одну мониторилку</h3><!--record-id-1208-->\n\n                \n                \n                \n                \n\n                <div record-id=\"1209\" class=\"meta\"><!--record-id-1210-->\n                  <span record-id=\"1211\" class=\"author\"><!--record-id-1212-->homecreate</span><!--record-id-1213-->\n                  •\n                  <span record-id=\"1214\" class=\"time\"><!--record-id-1215-->18 октября 2016 в 22:16</span><!--record-id-1216-->\n                </div><!--record-id-1217-->\n              </a><!--record-id-1218-->\n              <a record-id=\"1219\" href=\"/post/311502/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_similar_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1220-->10</a><!--record-id-1221-->\n          </div><!--record-id-1222-->\n          <div record-id=\"1223\" class=\"post\"><!--record-id-1224-->\n              <a record-id=\"1225\" href=\"https://m.habrahabr.ru/post/247555/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_similar_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1226-->\n                <h3 record-id=\"1227\" class=\"title\"><!--record-id-1228-->Когда никто не читает Хабр</h3><!--record-id-1229-->\n\n                \n                \n                \n                \n\n                <div record-id=\"1230\" class=\"meta\"><!--record-id-1231-->\n                  <span record-id=\"1232\" class=\"author\"><!--record-id-1233-->varagian</span><!--record-id-1234-->\n                  •\n                  <span record-id=\"1235\" class=\"time\"><!--record-id-1236-->13 января 2015 в 11:01</span><!--record-id-1237-->\n                </div><!--record-id-1238-->\n              </a><!--record-id-1239-->\n          
  21. unction') { ga('send', 'event', 'tm_block', 'mobile_similar_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1241-->29</a><!--record-id-1242-->\n          </div><!--record-id-1243-->\n          <div record-id=\"1244\" class=\"post\"><!--record-id-1245-->\n              <a record-id=\"1246\" href=\"https://m.habrahabr.ru/post/144497/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_similar_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1247-->\n                <h3 record-id=\"1248\" class=\"title\"><!--record-id-1249-->Никто не читает правил</h3><!--record-id-1250-->\n\n                \n                \n                \n                \n\n                <div record-id=\"1251\" class=\"meta\"><!--record-id-1252-->\n                  <span record-id=\"1253\" class=\"author\"><!--record-id-1254-->umputun</span><!--record-id-1255-->\n                  •\n                  <span record-id=\"1256\" class=\"time\"><!--record-id-1257-->24 мая 2012 в 22:26</span><!--record-id-1258-->\n                </div><!--record-id-1259-->\n              </a><!--record-id-1260-->\n              <a record-id=\"1261\" href=\"/post/144497/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_similar_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1262-->53</a><!--record-id-1263-->\n          </div><!--record-id-1264-->\n      </div><!--record-id-1265-->\n    </div><!--record-id-1266-->\n\n  \n\n  <div record-id=\"1267\" class=\"popular_posts\"><!--record-id-1268-->\n    <div record-id=\"1269\" class=\"title\"><!--record-id-1270-->Популярное за сутки</div><!--record-id-1271-->\n    <div record-id=\"1272\" class=\"posts\"><!--record-id-1273-->\n        <div record-id=\"1274\" class=\"post\"><!--record-id-1275-->\n            <a record-id=\"1276\" href=\"https://m.habrahabr.ru/post/333522/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1277-->\n              <h3 record-id=\"1278\" class=\"title\"><!--record-id-1279-->Яндекс открывает технологию машинного обучения CatBoost</h3><!--record-id-1280-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1281\" class=\"meta\"><!--record-id-1282-->\n                <span record-id=\"1283\" class=\"author\"><!--record-id-1284-->BarakAdama</span><!--record-id-1285-->\n                •\n                <span record-id=\"1286\" class=\"time\"><!--record-id-1287-->сегодня в 12:19</span><!--record-id-1288-->\n              </div><!--record-id-1289-->\n            </a><!--record-id-1290-->\n            <a record-id=\"1291\" href=\"/post/333522/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1292-->19</a><!--record-id-1293-->\n        </div><!--record-id-1294-->\n        <div record-id=\"1295\" class=\"post\"><!--record-id-1296-->\n            <a record-id=\"1297\" href=\"https://m.habrahabr.ru/post/333532/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1298-->\n              <h3 record-id=\"1299\" class=\"title\"><!--record-id-1300-->Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне</h3><!--record-id-1301-->\n\n              \n              \n              \n              <div record-id=\"1302\" class=\"flag sandbox\"><!--record-id-1303-->из песочницы</div><!--record-id-1304--> \n\n              <div record-id=\"1305\" class=\"meta\"><!--record-id-1306-->\n                <span record-id=\"1307\" class=\"author\"><!--record-id-1308-->Petrenuk</span><!--record-id-1309-->\n                •\n                <span record-id=\"1310
  22. div><!--record-id-1313-->\n            </a><!--record-id-1314-->\n            <a record-id=\"1315\" href=\"/post/333532/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1316-->14</a><!--record-id-1317-->\n        </div><!--record-id-1318-->\n        <div record-id=\"1319\" class=\"post\"><!--record-id-1320-->\n            <a record-id=\"1321\" href=\"https://m.habrahabr.ru/post/333510/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1322-->\n              <h3 record-id=\"1323\" class=\"title\"><!--record-id-1324-->Paradigm  —  Дизайн-система Mail.Ru Group, часть 1: Визуальный язык</h3><!--record-id-1325-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1326\" class=\"meta\"><!--record-id-1327-->\n                <span record-id=\"1328\" class=\"author\"><!--record-id-1329-->ASundiev</span><!--record-id-1330-->\n                •\n                <span record-id=\"1331\" class=\"time\"><!--record-id-1332-->вчера в 15:50</span><!--record-id-1333-->\n              </div><!--record-id-1334-->\n            </a><!--record-id-1335-->\n            <a record-id=\"1336\" href=\"/post/333510/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1337-->15</a><!--record-id-1338-->\n        </div><!--record-id-1339-->\n        <div record-id=\"1340\" class=\"post\"><!--record-id-1341-->\n            <a record-id=\"1342\" href=\"https://m.habrahabr.ru/post/332494/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1343-->\n              <h3 record-id=\"1344\" class=\"title\"><!--record-id-1345-->Постквантовая реинкарнация алгоритма Диффи-Хеллмана: вероятное будущее (изогении)</h3><!--record-id-1346-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1347\" class=\"meta\"><!--record-id-1348-->\n                <span record-id=\"1349\" class=\"author\"><!--record-id-1350-->Crittografo</span><!--record-id-1351-->\n                •\n                <span record-id=\"1352\" class=\"time\"><!--record-id-1353-->вчера в 16:57</span><!--record-id-1354-->\n              </div><!--record-id-1355-->\n            </a><!--record-id-1356-->\n            <a record-id=\"1357\" href=\"/post/332494/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1358-->8</a><!--record-id-1359-->\n        </div><!--record-id-1360-->\n        <div record-id=\"1361\" class=\"post\"><!--record-id-1362-->\n            <a record-id=\"1363\" href=\"https://m.habrahabr.ru/post/333528/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1364-->\n              <h3 record-id=\"1365\" class=\"title\"><!--record-id-1366-->Как тысячи игроков Eve Online помогают в расшифровке человеческого тела</h3><!--record-id-1367-->\n\n              \n              \n              \n              <div record-id=\"1368\" class=\"flag sandbox\"><!--record-id-1369-->из песочницы</div><!--record-id-1370--> \n\n              <div record-id=\"1371\" class=\"meta\"><!--record-id-1372-->\n                <span record-id=\"1373\" class=\"author\"><!--record-id-1374-->ruslanjf</span><!--record-id-1375-->\n                •\n                <span record-id=\"1376\" class=\"time\"><!--record-id-1377-->вчера в 16:38</span><!--record-id-1378-->\n      
  23. /\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_popular_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1382-->13</a><!--record-id-1383-->\n        </div><!--record-id-1384-->\n    </div><!--record-id-1385-->\n  </div><!--record-id-1386-->\n\n\n\n    \n\n  <div record-id=\"1387\" class=\"geektimes_posts\"><!--record-id-1388-->\n    <div record-id=\"1389\" class=\"title\"><!--record-id-1390-->Лучшее на Geektimes</div><!--record-id-1391-->\n    <div record-id=\"1392\" class=\"posts\"><!--record-id-1393-->\n        <div record-id=\"1394\" class=\"post\"><!--record-id-1395-->\n            <a record-id=\"1396\" href=\"https://m.geektimes.ru/post/291189/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1397-->\n              <h3 record-id=\"1398\" class=\"title\"><!--record-id-1399-->Мы нашли спутник МАЯК на орбите</h3><!--record-id-1400-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1401\" class=\"meta\"><!--record-id-1402-->\n                <span record-id=\"1403\" class=\"author\"><!--record-id-1404-->Sterpa</span><!--record-id-1405-->\n                •\n                <span record-id=\"1406\" class=\"time\"><!--record-id-1407-->вчера в 22:29</span><!--record-id-1408-->\n              </div><!--record-id-1409-->\n            </a><!--record-id-1410-->\n            <a record-id=\"1411\" href=\"https://m.geektimes.ru/post/291189/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1412-->60</a><!--record-id-1413-->\n        </div><!--record-id-1414-->\n        <div record-id=\"1415\" class=\"post\"><!--record-id-1416-->\n            <a record-id=\"1417\" href=\"https://m.geektimes.ru/post/291185/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1418-->\n              <h3 record-id=\"1419\" class=\"title\"><!--record-id-1420-->Ванечка</h3><!--record-id-1421-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1422\" class=\"meta\"><!--record-id-1423-->\n                <span record-id=\"1424\" class=\"author\"><!--record-id-1425-->ragequit</span><!--record-id-1426-->\n                •\n                <span record-id=\"1427\" class=\"time\"><!--record-id-1428-->вчера в 20:57</span><!--record-id-1429-->\n              </div><!--record-id-1430-->\n            </a><!--record-id-1431-->\n            <a record-id=\"1432\" href=\"https://m.geektimes.ru/post/291185/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1433-->110</a><!--record-id-1434-->\n        </div><!--record-id-1435-->\n        <div record-id=\"1436\" class=\"post\"><!--record-id-1437-->\n            <a record-id=\"1438\" href=\"https://m.geektimes.ru/post/291195/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1439-->\n              <h3 record-id=\"1440\" class=\"title\"><!--record-id-1441-->NucInc: к чёрту технику безопасности</h3><!--record-id-1442-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1443\" class=\"meta\"><!--record-id-1444-->\n                <span record-id=\"1445\" class=\"author\"><!--record-id-1446-->Tiberius</span><!--record-id-1447-->\n                •\n                <span record-id=\"1448\" class=\"time\"><!--record-id-1449-->сегодня в 08:21</span><!--record-id-1450-->\n              </div><!--record-id-1451-->\n            </a><!--record-id-1452-->\n            <a record-id
  24. mes.ru/post/291195/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1454-->37</a><!--record-id-1455-->\n        </div><!--record-id-1456-->\n        <div record-id=\"1457\" class=\"post\"><!--record-id-1458-->\n            <a record-id=\"1459\" href=\"https://m.geektimes.ru/post/291177/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1460-->\n              <h3 record-id=\"1461\" class=\"title\"><!--record-id-1462-->SoundCloud под угрозой закрытия, добровольцы собираются создать архивную копию всех файлов сервиса</h3><!--record-id-1463-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1464\" class=\"meta\"><!--record-id-1465-->\n                <span record-id=\"1466\" class=\"author\"><!--record-id-1467-->marks</span><!--record-id-1468-->\n                •\n                <span record-id=\"1469\" class=\"time\"><!--record-id-1470-->вчера в 17:27</span><!--record-id-1471-->\n              </div><!--record-id-1472-->\n            </a><!--record-id-1473-->\n            <a record-id=\"1474\" href=\"https://m.geektimes.ru/post/291177/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1475-->31</a><!--record-id-1476-->\n        </div><!--record-id-1477-->\n        <div record-id=\"1478\" class=\"post\"><!--record-id-1479-->\n            <a record-id=\"1480\" href=\"https://m.geektimes.ru/post/291173/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'post'); }\" class=\"post_inner\"><!--record-id-1481-->\n              <h3 record-id=\"1482\" class=\"title\"><!--record-id-1483-->Ученые напечатали мягкое сердце, которое работает как настоящее</h3><!--record-id-1484-->\n\n              \n              \n              \n              \n\n              <div record-id=\"1485\" class=\"meta\"><!--record-id-1486-->\n                <span record-id=\"1487\" class=\"author\"><!--record-id-1488-->krasandm</span><!--record-id-1489-->\n                •\n                <span record-id=\"1490\" class=\"time\"><!--record-id-1491-->вчера в 16:39</span><!--record-id-1492-->\n              </div><!--record-id-1493-->\n            </a><!--record-id-1494-->\n            <a record-id=\"1495\" href=\"https://m.geektimes.ru/post/291173/comments/\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'tm_block', 'mobile_geektimes_posts', 'comments'); }\" class=\"comments_count\"><!--record-id-1496-->10</a><!--record-id-1497-->\n        </div><!--record-id-1498-->\n    </div><!--record-id-1499-->\n  </div><!--record-id-1500-->\n\n\n  \n\n      </div><!--record-id-1501-->\n      <div record-id=\"1502\" id=\"footer\" class=\"footer\"><!--record-id-1503-->\n  <div record-id=\"1504\" class=\"footer__section\"><!--record-id-1505-->\n    <span record-id=\"1506\" class=\"footer__text\"><!--record-id-1507-->Мобильное приложение</span><!--record-id-1508-->\n    <div record-id=\"1509\" class=\"apps footer__apps js-apps\"><!--record-id-1510-->\n      <a record-id=\"1511\" href=\"https://appmetrica.yandex.com/serve/240693928167260216?utm_source=mobilTM&utm_medium=button&utm_campaign=appiOS\" class=\"apps__item js-app_ios hidden\" target=\"_blank\" onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'footer', 'links', 'ios_app'); }\"><!--record-id-1512-->\n        <img record-id=\"1513\" src=\"/images/apps/appstore_52.png\" height=\"52\"/><!--record-id-1514-->\n      </a><!--record-id-1515-->\n\n      <a record-id=\"1516\" href=\"https://appmetrica.yandex.com/serve/745097116363323173?id=ru.habrahabr&utm_sourc
  25. onclick=\"if (typeof ga === 'function') { ga('send', 'event', 'footer', 'links', 'android_app'); }\" style=\"display: block;\"><!--record-id-1517-->\n        <img record-id=\"1518\" src=\"/images/apps/gp_52.png\" height=\"52\"/><!--record-id-1519-->\n      </a><!--record-id-1520-->\n    </div><!--record-id-1521-->\n  </div><!--record-id-1522-->\n\n  <div record-id=\"1523\" class=\"footer__section\"><a record-id=\"1524\" href=\"https://habrahabr.ru/post/333532/?mobile=no\" class=\"footer__text\"><!--record-id-1525-->Полная версия</a></div><!--record-id-1526-->\n  <div record-id=\"1527\" class=\"footer__section footer__text\"><!--record-id-1528-->2006 – 2017 © TM</div><!--record-id-1529-->\n</div><!--record-id-1530-->\n    </div><!--record-id-1531-->\n    <div record-id=\"1532\" id=\"sidebar_overlay\"></div><!--record-id-1533-->\n\n<div record-id=\"1534\" id=\"sidebar\"><!--record-id-1535-->\n    <a record-id=\"1536\" href=\"https://habrahabr.ru/auth/login/\" class=\"head\"><!--record-id-1537-->\n      <img record-id=\"1538\" src=\"/images/mobile.default_avatar.png\" alt=\"\"/><!--record-id-1539-->\n      <span record-id=\"1540\" class=\"username\"><!--record-id-1541-->Вход на сайт</span><!--record-id-1542-->\n    </a><!--record-id-1543-->\n\n  <div record-id=\"1544\" class=\"menu\"><!--record-id-1545-->\n    <a record-id=\"1546\" href=\"/\" class=\"posts\"><!--record-id-1547-->Лучшие</a><!--record-id-1548-->\n    <a record-id=\"1549\" href=\"/all/\" class=\"posts\"><!--record-id-1550-->Все подряд</a><!--record-id-1551-->\n\n\n    <a record-id=\"1552\" href=\"/flows/\" class=\"hubs\"><!--record-id-1553-->Хабы</a><!--record-id-1554-->\n    <a record-id=\"1555\" href=\"/companies/\" class=\"companies\"><!--record-id-1556-->Компании</a><!--record-id-1557-->\n\n  </div><!--record-id-1558-->\n</div><!--record-id-1559-->\n\n    <!--record-id-1561-->\n\n    \n<!--record-id-1562--><!-- Yandex.Metrika counter --><!--record-id-1563-->\n<!--record-id-1565-->\n<noscript record-id=\"1566\">&lt;div&gt;&lt;img src=\"//mc.yandex.ru/watch/24049213\" style=\"position:absolute; left:-9999px;\" alt=\"\" /&gt;&lt;/div&gt;</noscript><!--record-id-1567-->\n<!--record-id-1568--><!-- /Yandex.Metrika counter --><!--record-id-1569-->\n\n    \n    <!--record-id-1571-->\n    \n  \n\n<div record-id=\"1572\" class=\"advblock advertblock ammblock b-banner b-media-banner pub_300x250 pub_300x250m medium_rectangle_300_250 pub_728x90 leaderboard_728_90 wide_skyscraper_160_600 wide_skyscraper_160x600 text-ad textAd text_ad text_ads text-ads text-ad-links ad_text ad_text banner_text text-banner b-rb\" style=\"position: absolute !important; top: -9999px !important; left: -9999px !important; width: 1px !important; height: 1px !important;\"></div><iframe record-id=\"1573\" src=\"https://content.adriver.ru/banners/0002186/0002186173/0/l6.html?626911&0&1&0&8836022&0&0&129&217.12.196.142&merle&0\" style=\"height: 10px; width: 10px; position: absolute; left: -10000px; top: -10000px;\"></iframe><iframe record-id=\"1574\" src=\"https://content.adriver.ru/banners/0002186/0002186173/0/l6.html?626911&0&1&0&3658010&0&0&129&217.12.196.142&merle&0\" style=\"height: 10px; width: 10px; position: absolute; left: -10000px; top: -10000px;\"></iframe></body>","host":"m.habrahabr.ru","title":"Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне / Хабрахабр","absoluteTimeStamp":125824,"htmlAttributes":{},"screenWidth":360,"screenHeight":616,"activeElement":207,"scrolls":{"207":{"top":1174,"left":0}}},"_initialStateIndex":2,"_recordName":"1500379941701","_timelineMaxIndex":0,"_userID":28,"_id":"7"}
Advertisement
Add Comment
Please, Sign In to add comment